@crowdin/app-project-module 1.8.1 → 1.10.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.
Files changed (42) hide show
  1. package/out/middlewares/crowdin-client.js +5 -5
  2. package/out/middlewares/integration-access-denied.d.ts +1 -1
  3. package/out/middlewares/integration-access-denied.js +2 -35
  4. package/out/middlewares/ui-module.js +3 -3
  5. package/out/modules/custom-mt/index.js +2 -1
  6. package/out/modules/file-processing/handlers/file-download.js +2 -1
  7. package/out/modules/file-processing/handlers/pre-post-process.js +2 -1
  8. package/out/modules/file-processing/handlers/translations-alignment.js +2 -1
  9. package/out/modules/file-processing/index.js +3 -2
  10. package/out/modules/file-processing/util/folder.d.ts +1 -0
  11. package/out/modules/file-processing/util/folder.js +13 -0
  12. package/out/modules/install.js +7 -7
  13. package/out/modules/integration/handlers/integration-logout.js +2 -35
  14. package/out/modules/integration/handlers/job-list.js +4 -1
  15. package/out/modules/integration/handlers/oauth-login.js +2 -2
  16. package/out/modules/integration/handlers/settings-save.js +56 -41
  17. package/out/modules/integration/handlers/sync-settings-save.js +57 -3
  18. package/out/modules/integration/types.d.ts +7 -0
  19. package/out/modules/integration/util/cron.js +7 -40
  20. package/out/modules/integration/util/defaults.js +2 -35
  21. package/out/modules/integration/util/files.js +19 -7
  22. package/out/modules/integration/util/job.d.ts +4 -3
  23. package/out/modules/integration/util/job.js +8 -40
  24. package/out/modules/integration/util/types.d.ts +4 -2
  25. package/out/modules/integration/util/types.js +2 -0
  26. package/out/modules/integration/util/webhooks.d.ts +1 -1
  27. package/out/modules/integration/util/webhooks.js +7 -7
  28. package/out/static/ui/form.bundle.js +99 -44
  29. package/out/static/ui/form.bundle.js.map +1 -1
  30. package/out/static/ui/main.bundle.js +94 -3
  31. package/out/static/ui/main.bundle.js.map +1 -1
  32. package/out/types.d.ts +45 -1
  33. package/out/types.js +11 -1
  34. package/out/util/app-functions/crowdin.d.ts +104 -0
  35. package/out/util/app-functions/crowdin.js +245 -0
  36. package/out/util/app-functions/token.d.ts +71 -0
  37. package/out/util/app-functions/token.js +192 -0
  38. package/out/util/connection.js +11 -12
  39. package/out/util/credentials-masker.js +2 -2
  40. package/out/util/index.js +2 -2
  41. package/out/util/subscription.js +3 -3
  42. package/package.json +26 -2
@@ -12,21 +12,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.prepareCrowdinRequest = prepareCrowdinRequest;
13
13
  exports.default = handle;
14
14
  exports.getToken = getToken;
15
- const crowdin_apps_functions_1 = require("@crowdin/crowdin-apps-functions");
15
+ const api_1 = require("../modules/api/api");
16
16
  const storage_1 = require("../storage");
17
17
  const util_1 = require("../util");
18
- const api_1 = require("../modules/api/api");
19
18
  const connection_1 = require("../util/connection");
20
- const integration_access_denied_1 = require("./integration-access-denied");
21
19
  const logger_1 = require("../util/logger");
22
20
  const subscription_1 = require("../util/subscription");
21
+ const integration_access_denied_1 = require("./integration-access-denied");
22
+ const token_1 = require("../util/app-functions/token");
23
23
  function prepareCrowdinRequest(_a) {
24
24
  return __awaiter(this, arguments, void 0, function* ({ jwtToken, config, optional = false, checkSubscriptionExpiration = true, moduleKey, }) {
25
25
  (0, logger_1.log)('Validating jwt token from incoming request');
26
- const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(jwtToken, config.clientSecret, config.jwtValidationOptions);
26
+ const jwtPayload = yield (0, token_1.validateJwtToken)(jwtToken, config.clientSecret, config.jwtValidationOptions);
27
27
  const context = {
28
28
  jwtPayload,
29
- clientId: (0, crowdin_apps_functions_1.constructCrowdinIdFromJwtPayload)(jwtPayload),
29
+ clientId: (0, token_1.constructCrowdinIdFromJwtPayload)(jwtPayload),
30
30
  crowdinId: `${jwtPayload.domain || jwtPayload.context.organization_id}`,
31
31
  appIdentifier: config.identifier,
32
32
  };
@@ -1,7 +1,7 @@
1
1
  import Crowdin from '@crowdin/crowdin-api-client';
2
2
  import { Response } from 'express';
3
- import { CrowdinClientRequest } from '../types';
4
3
  import { IntegrationRequest } from '../modules/integration/types';
4
+ import { CrowdinClientRequest } from '../types';
5
5
  interface OwnerInfo {
6
6
  name: string;
7
7
  id: number;
@@ -1,37 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
3
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
4
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -44,15 +11,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
44
11
  Object.defineProperty(exports, "__esModule", { value: true });
45
12
  exports.getIntegrationManagedBy = getIntegrationManagedBy;
46
13
  exports.renderIntegrationAccessDenied = renderIntegrationAccessDenied;
47
- const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
48
14
  const jsx_renderer_1 = require("../util/jsx-renderer");
49
15
  const logger_1 = require("../util/logger");
16
+ const token_1 = require("../util/app-functions/token");
50
17
  function getIntegrationManagedBy(_a) {
51
18
  return __awaiter(this, arguments, void 0, function* ({ ownerIds, crowdinApiClient, clientId, }) {
52
19
  if (!ownerIds.length) {
53
20
  return [];
54
21
  }
55
- const projectId = crowdinAppFunctions.getProjectId(clientId);
22
+ const projectId = (0, token_1.getProjectId)(clientId);
56
23
  let owners = [];
57
24
  try {
58
25
  owners =
@@ -10,10 +10,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.default = handle;
13
- const crowdin_apps_functions_1 = require("@crowdin/crowdin-apps-functions");
14
13
  const storage_1 = require("../storage");
15
14
  const types_1 = require("../types");
16
15
  const util_1 = require("../util");
16
+ const token_1 = require("../util/app-functions/token");
17
17
  const connection_1 = require("../util/connection");
18
18
  const jsx_renderer_1 = require("../util/jsx-renderer");
19
19
  const logger_1 = require("../util/logger");
@@ -40,7 +40,7 @@ function handle({ config, allowUnauthorized = false, moduleType, }) {
40
40
  return res.status(403).send({ error: 'Access denied' });
41
41
  }
42
42
  (0, logger_1.log)('Validating jwt token from incoming request');
43
- const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(jwtToken, config.clientSecret, config.jwtValidationOptions);
43
+ const jwtPayload = yield (0, token_1.validateJwtToken)(jwtToken, config.clientSecret, config.jwtValidationOptions);
44
44
  const id = `${jwtPayload.domain || jwtPayload.context.organization_id}`;
45
45
  if (moduleType && jwtPayload.module && jwtPayload.module !== moduleType) {
46
46
  (0, logger_1.temporaryErrorDebug)('Access denied: ui-module', req);
@@ -48,7 +48,7 @@ function handle({ config, allowUnauthorized = false, moduleType, }) {
48
48
  }
49
49
  const context = {
50
50
  jwtPayload,
51
- clientId: (0, crowdin_apps_functions_1.constructCrowdinIdFromJwtPayload)(jwtPayload),
51
+ clientId: (0, token_1.constructCrowdinIdFromJwtPayload)(jwtPayload),
52
52
  crowdinId: id,
53
53
  appIdentifier: config.identifier,
54
54
  };
@@ -8,6 +8,7 @@ const crowdin_client_1 = __importDefault(require("../../middlewares/crowdin-clie
8
8
  const util_1 = require("../../util");
9
9
  const normalize_module_1 = require("../../util/normalize-module");
10
10
  const file_download_1 = __importDefault(require("../file-processing/handlers/file-download"));
11
+ const folder_1 = require("../file-processing/util/folder");
11
12
  const translate_1 = __importDefault(require("./handlers/translate"));
12
13
  function register({ config, app }) {
13
14
  var _a;
@@ -18,7 +19,7 @@ function register({ config, app }) {
18
19
  const isSingle = items.length === 1;
19
20
  for (const [index, mt] of items.entries()) {
20
21
  const key = (_a = mt.key) !== null && _a !== void 0 ? _a : (0, normalize_module_1.resolveInstanceKey)({ identifier: config.identifier, suffix: 'mt', item: mt, index, isSingle });
21
- const folder = mt.filesFolder || config.dbFolder;
22
+ const folder = (0, folder_1.resolveModuleFilesFolder)(config.dbFolder, mt.filesFolder);
22
23
  const logoPath = isSingle ? '/logo/mt' : `/logo/mt-${key}`;
23
24
  const translatePath = isSingle ? '/mt/translate' : `/mt/${key}/translate`;
24
25
  const downloadPath = isSingle ? '/file/download/custom-mt' : `/file/download/custom-mt-${key}`;
@@ -17,8 +17,9 @@ const fs_1 = __importDefault(require("fs"));
17
17
  const path_1 = __importDefault(require("path"));
18
18
  const util_1 = require("../../../util");
19
19
  const logger_1 = require("../../../util/logger");
20
+ const folder_1 = require("../util/folder");
20
21
  function handle(config, processingConfig, folderName) {
21
- const folder = processingConfig.filesFolder || config.dbFolder;
22
+ const folder = (0, folder_1.resolveModuleFilesFolder)(config.dbFolder, processingConfig.filesFolder);
22
23
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
23
24
  if (config.fileStore) {
24
25
  const fileContent = yield config.fileStore.getFile(req.query.file);
@@ -17,9 +17,10 @@ const fs_1 = __importDefault(require("fs"));
17
17
  const path_1 = __importDefault(require("path"));
18
18
  const util_1 = require("../../../util");
19
19
  const types_1 = require("../types");
20
+ const folder_1 = require("../util/folder");
20
21
  const files_1 = require("../util/files");
21
22
  function handle(baseConfig, config, folderName) {
22
- const folderPath = config.filesFolder || baseConfig.dbFolder;
23
+ const folderPath = (0, folder_1.resolveModuleFilesFolder)(baseConfig.dbFolder, config.filesFolder);
23
24
  if (!baseConfig.fileStore) {
24
25
  if (!fs_1.default.existsSync(path_1.default.join(folderPath, folderName))) {
25
26
  fs_1.default.mkdirSync(path_1.default.join(folderPath, folderName), { recursive: true });
@@ -16,9 +16,10 @@ exports.default = handle;
16
16
  const fs_1 = __importDefault(require("fs"));
17
17
  const path_1 = __importDefault(require("path"));
18
18
  const util_1 = require("../../../util");
19
+ const folder_1 = require("../util/folder");
19
20
  const files_1 = require("../util/files");
20
21
  function handle(baseConfig, config, folderName) {
21
- const folderPath = config.filesFolder || baseConfig.dbFolder;
22
+ const folderPath = (0, folder_1.resolveModuleFilesFolder)(baseConfig.dbFolder, config.filesFolder);
22
23
  if (!fs_1.default.existsSync(path_1.default.join(folderPath, folderName))) {
23
24
  fs_1.default.mkdirSync(path_1.default.join(folderPath, folderName), { recursive: true });
24
25
  }
@@ -17,6 +17,7 @@ const pre_post_process_1 = __importDefault(require("./handlers/pre-post-process"
17
17
  const translations_alignment_1 = __importDefault(require("./handlers/translations-alignment"));
18
18
  const types_1 = require("./types");
19
19
  const defaults_1 = require("./util/defaults");
20
+ const folder_1 = require("./util/folder");
20
21
  function registerCustomFileFormat({ config, app }) {
21
22
  var _a;
22
23
  if (!config.customFileFormat) {
@@ -35,7 +36,7 @@ function registerCustomFileFormat({ config, app }) {
35
36
  moduleKey: key,
36
37
  }), (0, custom_file_format_1.default)({
37
38
  baseUrl: config.baseUrl,
38
- folder: ff.filesFolder || config.dbFolder,
39
+ folder: (0, folder_1.resolveModuleFilesFolder)(config.dbFolder, ff.filesFolder),
39
40
  config: ff,
40
41
  fileStore: config.fileStore,
41
42
  }));
@@ -50,7 +51,7 @@ function registerCustomFileFormat({ config, app }) {
50
51
  checkSubscriptionExpiration: true,
51
52
  }), (0, custom_file_format_1.default)({
52
53
  baseUrl: config.baseUrl,
53
- folder: ff.filesFolder || config.dbFolder,
54
+ folder: (0, folder_1.resolveModuleFilesFolder)(config.dbFolder, ff.filesFolder),
54
55
  config: ff,
55
56
  fileStore: config.fileStore,
56
57
  }));
@@ -0,0 +1 @@
1
+ export declare function resolveModuleFilesFolder(dbFolder: string, filesFolder?: string): string;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveModuleFilesFolder = resolveModuleFilesFolder;
4
+ const LAMBDA_TMP_FOLDER = '/tmp';
5
+ function resolveModuleFilesFolder(dbFolder, filesFolder) {
6
+ if (filesFolder) {
7
+ return filesFolder;
8
+ }
9
+ if (process.env.AWS_LAMBDA_FUNCTION_NAME) {
10
+ return LAMBDA_TMP_FOLDER;
11
+ }
12
+ return dbFolder;
13
+ }
@@ -10,12 +10,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.default = handle;
13
- const crowdin_apps_functions_1 = require("@crowdin/crowdin-apps-functions");
14
- const types_1 = require("../types");
15
13
  const storage_1 = require("../storage");
14
+ const types_1 = require("../types");
16
15
  const util_1 = require("../util");
17
- const logger_1 = require("../util/logger");
16
+ const token_1 = require("../util/app-functions/token");
18
17
  const connection_1 = require("../util/connection");
18
+ const logger_1 = require("../util/logger");
19
19
  function handle(config) {
20
20
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
21
21
  const event = req.body;
@@ -57,7 +57,7 @@ function fetchToken(config, event) {
57
57
  return __awaiter(this, void 0, void 0, function* () {
58
58
  var _a, _b, _c, _d;
59
59
  if (config.authenticationType === types_1.AuthenticationType.CODE) {
60
- const token = yield (0, crowdin_apps_functions_1.generateOAuthToken)({
60
+ const token = yield (0, token_1.generateOAuthToken)({
61
61
  clientId: config.clientId,
62
62
  clientSecret: config.clientSecret,
63
63
  code: event.code || '',
@@ -70,7 +70,7 @@ function fetchToken(config, event) {
70
70
  };
71
71
  }
72
72
  if (config.authenticationType === types_1.AuthenticationType.AGENT) {
73
- const token = yield (0, crowdin_apps_functions_1.fetchAgentToken)({
73
+ const token = yield (0, token_1.fetchAgentToken)({
74
74
  appId: config.identifier,
75
75
  appSecret: event.appSecret,
76
76
  clientId: config.clientId,
@@ -87,7 +87,7 @@ function fetchToken(config, event) {
87
87
  };
88
88
  }
89
89
  if (config.authenticationType === types_1.AuthenticationType.APP_WITH_CODE) {
90
- const token = yield (0, crowdin_apps_functions_1.fetchAppWithCodeToken)({
90
+ const token = yield (0, token_1.fetchAppWithCodeToken)({
91
91
  appId: config.identifier,
92
92
  appSecret: event.appSecret,
93
93
  clientId: config.clientId,
@@ -103,7 +103,7 @@ function fetchToken(config, event) {
103
103
  refreshToken: '',
104
104
  };
105
105
  }
106
- const token = yield (0, crowdin_apps_functions_1.fetchAppToken)({
106
+ const token = yield (0, token_1.fetchAppToken)({
107
107
  appId: config.identifier,
108
108
  appSecret: event.appSecret,
109
109
  clientId: config.clientId,
@@ -1,37 +1,4 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
3
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
4
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -45,13 +12,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
45
12
  exports.default = handle;
46
13
  const storage_1 = require("../../../storage");
47
14
  const util_1 = require("../../../util");
15
+ const token_1 = require("../../../util/app-functions/token");
48
16
  const logger_1 = require("../../../util/logger");
49
17
  const subscription_1 = require("../../../util/subscription");
50
18
  const webhooks_1 = require("../util/webhooks");
51
- const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
52
19
  function handle(config, integration) {
53
20
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
54
- const { userId } = crowdinAppFunctions.parseCrowdinId(req.crowdinContext.clientId);
21
+ const { userId } = (0, token_1.parseCrowdinId)(req.crowdinContext.clientId);
55
22
  const isCredentialOwner = +userId === +req.crowdinContext.jwtPayload.sub;
56
23
  if (!isCredentialOwner && !req.canForceIntegrationLogout) {
57
24
  return res.status(403).send({ error: 'Access denied' });
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.default = handle;
13
13
  const util_1 = require("../../../util");
14
14
  const storage_1 = require("../../../storage");
15
+ const types_1 = require("../util/types");
15
16
  function handle() {
16
17
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
17
18
  const limit = req.query.limit ? parseInt(req.query.limit, 10) : 25;
@@ -28,7 +29,9 @@ function handle() {
28
29
  res.send([]);
29
30
  return;
30
31
  }
31
- const filteredJobs = jobs.map((job) => {
32
+ const filteredJobs = jobs
33
+ .filter((job) => job.type !== types_1.JobType.INTEGRATION_SETTINGS_SAVE)
34
+ .map((job) => {
32
35
  var _a;
33
36
  const baseJob = {
34
37
  id: job.id,
@@ -13,10 +13,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.default = handle;
16
- const crowdin_apps_functions_1 = require("@crowdin/crowdin-apps-functions");
17
16
  const axios_1 = __importDefault(require("axios"));
18
17
  const storage_1 = require("../../../storage");
19
18
  const util_1 = require("../../../util");
19
+ const token_1 = require("../../../util/app-functions/token");
20
20
  const jsx_renderer_1 = require("../../../util/jsx-renderer");
21
21
  const logger_1 = require("../../../util/logger");
22
22
  const defaults_1 = require("../util/defaults");
@@ -31,7 +31,7 @@ function handle(config, integration) {
31
31
  (0, logger_1.log)(`Received request from OAuth login callback. Code ${code}`);
32
32
  (0, logger_1.log)(`Received request from OAuth login callback. State ${state}`);
33
33
  const clientId = Buffer.from(state, 'base64').toString();
34
- const { organization } = (0, crowdin_apps_functions_1.parseCrowdinId)(clientId);
34
+ const { organization } = (0, token_1.parseCrowdinId)(clientId);
35
35
  const redirectUri = `${config.baseUrl}${(0, defaults_1.getOauthRoute)(integration)}`;
36
36
  try {
37
37
  const oauthLogin = integration.oauthLogin;
@@ -16,6 +16,8 @@ const snapshot_1 = require("../util/snapshot");
16
16
  const webhooks_1 = require("../util/webhooks");
17
17
  const types_1 = require("../types");
18
18
  const cron_1 = require("../util/cron");
19
+ const job_1 = require("../util/job");
20
+ const types_2 = require("../util/types");
19
21
  function handle(config, integration) {
20
22
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
21
23
  const settings = req.body.config;
@@ -42,46 +44,59 @@ function handle(config, integration) {
42
44
  }
43
45
  }
44
46
  const clientId = req.crowdinContext.clientId;
45
- req.logInfo(`Saving settings ${JSON.stringify(settings, null, 2)}`);
46
- const integrationConfig = yield (0, storage_1.getStorage)().getIntegrationConfig(clientId);
47
- if (!integrationConfig) {
48
- yield (0, storage_1.getStorage)().saveIntegrationConfig(clientId, req.crowdinContext.crowdinId, JSON.stringify(settings));
49
- }
50
- else {
51
- yield (0, storage_1.getStorage)().updateIntegrationConfig(clientId, JSON.stringify(settings));
52
- }
53
- if (integration.webhooks) {
54
- yield (0, webhooks_1.registerWebhooks)({
55
- config,
56
- integration,
57
- client: req.crowdinApiClient,
58
- crowdinContext: req.crowdinContext,
59
- credentials: req.integrationCredentials,
60
- settings,
61
- });
62
- }
63
- else {
64
- if (settings === null || settings === void 0 ? void 0 : settings['new-crowdin-files']) {
65
- (0, snapshot_1.createOrUpdateFileSnapshot)(config, integration, req, types_1.Provider.CROWDIN);
66
- }
67
- if (settings === null || settings === void 0 ? void 0 : settings['new-integration-files']) {
68
- (0, snapshot_1.createOrUpdateFileSnapshot)(config, integration, req, types_1.Provider.INTEGRATION);
69
- }
70
- }
71
- if (integration.syncNewElements) {
72
- yield (0, cron_1.createOrUpdateSyncSettings)({
73
- req,
74
- files: {},
75
- provider: types_1.Provider.CROWDIN,
76
- onlyCreate: true,
77
- });
78
- yield (0, cron_1.createOrUpdateSyncSettings)({
79
- req,
80
- files: [],
81
- provider: types_1.Provider.INTEGRATION,
82
- onlyCreate: true,
83
- });
84
- }
85
- res.status(204).end();
47
+ yield (0, job_1.runAsJob)({
48
+ integrationId: clientId,
49
+ crowdinId: req.crowdinContext.crowdinId,
50
+ type: types_2.JobType.INTEGRATION_SETTINGS_SAVE,
51
+ title: 'Save settings',
52
+ payload: req.body,
53
+ res,
54
+ projectId: req.crowdinContext.jwtPayload.context.project_id,
55
+ client: req.crowdinApiClient,
56
+ jobType: types_2.JobClientType.HIDDEN,
57
+ jobStoreType: integration.jobStoreType,
58
+ jobCallback: () => __awaiter(this, void 0, void 0, function* () {
59
+ req.logInfo(`Saving settings ${JSON.stringify(settings, null, 2)}`);
60
+ const integrationConfig = yield (0, storage_1.getStorage)().getIntegrationConfig(clientId);
61
+ if (!integrationConfig) {
62
+ yield (0, storage_1.getStorage)().saveIntegrationConfig(clientId, req.crowdinContext.crowdinId, JSON.stringify(settings));
63
+ }
64
+ else {
65
+ yield (0, storage_1.getStorage)().updateIntegrationConfig(clientId, JSON.stringify(settings));
66
+ }
67
+ if (integration.webhooks) {
68
+ yield (0, webhooks_1.registerWebhooks)({
69
+ config,
70
+ integration,
71
+ client: req.crowdinApiClient,
72
+ crowdinContext: req.crowdinContext,
73
+ credentials: req.integrationCredentials,
74
+ settings,
75
+ });
76
+ }
77
+ else {
78
+ if (settings === null || settings === void 0 ? void 0 : settings['new-crowdin-files']) {
79
+ (0, snapshot_1.createOrUpdateFileSnapshot)(config, integration, req, types_1.Provider.CROWDIN);
80
+ }
81
+ if (settings === null || settings === void 0 ? void 0 : settings['new-integration-files']) {
82
+ (0, snapshot_1.createOrUpdateFileSnapshot)(config, integration, req, types_1.Provider.INTEGRATION);
83
+ }
84
+ }
85
+ if (integration.syncNewElements) {
86
+ yield (0, cron_1.createOrUpdateSyncSettings)({
87
+ req,
88
+ files: {},
89
+ provider: types_1.Provider.CROWDIN,
90
+ onlyCreate: true,
91
+ });
92
+ yield (0, cron_1.createOrUpdateSyncSettings)({
93
+ req,
94
+ files: [],
95
+ provider: types_1.Provider.INTEGRATION,
96
+ onlyCreate: true,
97
+ });
98
+ }
99
+ }),
100
+ });
86
101
  }));
87
102
  }
@@ -11,15 +11,33 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.default = handle;
13
13
  const util_1 = require("../../../util");
14
+ const storage_1 = require("../../../storage");
14
15
  const cron_1 = require("../util/cron");
15
16
  const snapshot_1 = require("../util/snapshot");
16
17
  const files_1 = require("../util/files");
17
18
  const job_1 = require("../util/job");
18
19
  const types_1 = require("../util/types");
19
20
  const types_2 = require("../types");
21
+ const SUPPORTED_SCHEDULE_VALUES = new Set(['0', '1', '3', '6', '12', '24']);
22
+ function isScheduleDisabled(schedule) {
23
+ return schedule === undefined || schedule === null || String(schedule) === '0';
24
+ }
25
+ function getAutoEnabledSchedule(integration) {
26
+ var _a;
27
+ const configuredValue = String((_a = integration.autoEnableScheduleOnAutoSync) !== null && _a !== void 0 ? _a : '12');
28
+ return SUPPORTED_SCHEDULE_VALUES.has(configuredValue) ? configuredValue : '12';
29
+ }
30
+ function getScheduleLabel(schedule) {
31
+ return schedule === '1' ? '1 hour' : `${schedule} hours`;
32
+ }
20
33
  function handle(config, integration) {
21
34
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
35
+ var _a;
22
36
  const { files, provider, expandIntegrationFolders, hasLoadMoreElements, folderIds } = req.body;
37
+ const clientId = req.crowdinContext.clientId;
38
+ const autoEnabledSchedule = getAutoEnabledSchedule(integration);
39
+ let scheduleAutoEnabled = false;
40
+ const scheduleMessage = `Auto Sync requires a sync schedule. It has been automatically set to every ${getScheduleLabel(autoEnabledSchedule)}. You can adjust this in the app settings.`;
23
41
  if (req.isApiCall) {
24
42
  if (!files || !provider) {
25
43
  return res.status(400).json({
@@ -36,8 +54,23 @@ function handle(config, integration) {
36
54
  });
37
55
  }
38
56
  }
57
+ if (autoEnabledSchedule !== '0' && isScheduleDisabled((_a = req.integrationSettings) === null || _a === void 0 ? void 0 : _a.schedule)) {
58
+ const integrationConfig = yield (0, storage_1.getStorage)().getIntegrationConfig(clientId);
59
+ const currentSettings = (integrationConfig === null || integrationConfig === void 0 ? void 0 : integrationConfig.config)
60
+ ? JSON.parse(integrationConfig.config)
61
+ : req.integrationSettings || {};
62
+ const nextSettings = Object.assign(Object.assign({}, currentSettings), { schedule: autoEnabledSchedule });
63
+ if (!integrationConfig) {
64
+ yield (0, storage_1.getStorage)().saveIntegrationConfig(clientId, req.crowdinContext.crowdinId, JSON.stringify(nextSettings));
65
+ }
66
+ else {
67
+ yield (0, storage_1.getStorage)().updateIntegrationConfig(clientId, JSON.stringify(nextSettings));
68
+ }
69
+ req.integrationSettings = nextSettings;
70
+ scheduleAutoEnabled = true;
71
+ }
39
72
  yield (0, job_1.runAsJob)({
40
- integrationId: req.crowdinContext.clientId,
73
+ integrationId: clientId,
41
74
  crowdinId: req.crowdinContext.crowdinId,
42
75
  type: `${provider}SyncSettingsSave`,
43
76
  title: 'Save sync settings',
@@ -49,7 +82,16 @@ function handle(config, integration) {
49
82
  jobStoreType: integration.jobStoreType,
50
83
  initiatedBy: String(req.crowdinContext.jwtPayload.context.user_id),
51
84
  jobCallback: (job) => __awaiter(this, void 0, void 0, function* () {
52
- var _a;
85
+ var _a, _b, _c, _d, _e;
86
+ if (scheduleAutoEnabled) {
87
+ const { isCanceled } = yield job.update({ info: scheduleMessage });
88
+ if (isCanceled) {
89
+ return;
90
+ }
91
+ }
92
+ if (types_1.JobStatus.CANCELED === ((_a = (yield job.get())) === null || _a === void 0 ? void 0 : _a.status)) {
93
+ return;
94
+ }
53
95
  if (Array.isArray(expandIntegrationFolders) && expandIntegrationFolders.length) {
54
96
  const expandedFiles = hasLoadMoreElements
55
97
  ? yield (0, files_1.expandFilesTreeWithPagination)(expandIntegrationFolders, req, integration, job)
@@ -64,6 +106,9 @@ function handle(config, integration) {
64
106
  type: node.type,
65
107
  }));
66
108
  req.logInfo(`Expanded ${allFiles.length} files for auto-sync`);
109
+ if (types_1.JobStatus.CANCELED === ((_b = (yield job.get())) === null || _b === void 0 ? void 0 : _b.status)) {
110
+ return;
111
+ }
67
112
  yield (0, cron_1.createOrUpdateSyncSettings)({
68
113
  req,
69
114
  files: (0, util_1.uniqBy)([...files, ...allFiles], 'id'),
@@ -71,6 +116,9 @@ function handle(config, integration) {
71
116
  });
72
117
  }
73
118
  else {
119
+ if (types_1.JobStatus.CANCELED === ((_c = (yield job.get())) === null || _c === void 0 ? void 0 : _c.status)) {
120
+ return;
121
+ }
74
122
  yield (0, cron_1.createOrUpdateSyncSettings)({
75
123
  req,
76
124
  files: (0, files_1.prepareSyncFiles)(files),
@@ -83,11 +131,17 @@ function handle(config, integration) {
83
131
  ? (0, files_1.hasFolders)(syncFiles)
84
132
  : Array.isArray(folderIds) && folderIds.length > 0;
85
133
  const needsSnapshot = !integration.webhooks &&
86
- ((_a = integration.syncNewElements) === null || _a === void 0 ? void 0 : _a[provider]) &&
134
+ ((_d = integration.syncNewElements) === null || _d === void 0 ? void 0 : _d[provider]) &&
87
135
  (settings[`new-${provider}-files`] || hasSyncedFolders);
88
136
  if (needsSnapshot) {
137
+ if (types_1.JobStatus.CANCELED === ((_e = (yield job.get())) === null || _e === void 0 ? void 0 : _e.status)) {
138
+ return;
139
+ }
89
140
  yield (0, snapshot_1.createOrUpdateFileSnapshot)(config, integration, req, provider, job);
90
141
  }
142
+ if (scheduleAutoEnabled) {
143
+ yield job.update({ info: scheduleMessage });
144
+ }
91
145
  }),
92
146
  });
93
147
  }));
@@ -157,6 +157,13 @@ export interface IntegrationLogic extends ModuleKey {
157
157
  crowdin: boolean;
158
158
  integration: boolean;
159
159
  };
160
+ /**
161
+ * Schedule value that will be auto-applied when user enables Auto Sync while current schedule is disabled.
162
+ * Supported values are: '0', '1', '3', '6', '12', '24'.
163
+ * Use '0' to disable this auto-apply behavior.
164
+ * @default '12'
165
+ */
166
+ autoEnableScheduleOnAutoSync?: '0' | '1' | '3' | '6' | '12' | '24';
160
167
  /**
161
168
  * Enable file filtering
162
169
  */