@crowdin/app-project-module 1.5.5 → 1.6.1

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.
@@ -15,10 +15,11 @@ export declare function prepareCrowdinRequest({ jwtToken, config, optional, chec
15
15
  client?: Crowdin;
16
16
  subscriptionInfo?: SubscriptionInfo;
17
17
  }>;
18
- export default function handle({ config, optional, checkSubscriptionExpiration, moduleKey, }: {
18
+ export default function handle({ config, optional, checkSubscriptionExpiration, moduleKey, isIntegration, }: {
19
19
  config: Config;
20
20
  optional: boolean;
21
21
  checkSubscriptionExpiration: boolean;
22
22
  moduleKey?: string[] | string | undefined;
23
+ isIntegration?: boolean;
23
24
  }): (req: import("express").Request | CrowdinClientRequest, res: Response, next: Function) => void;
24
25
  export declare function getToken(req: CrowdinClientRequest): string | undefined;
@@ -17,6 +17,7 @@ const storage_1 = require("../storage");
17
17
  const util_1 = require("../util");
18
18
  const api_1 = require("../modules/api/api");
19
19
  const connection_1 = require("../util/connection");
20
+ const integration_access_denied_1 = require("./integration-access-denied");
20
21
  const logger_1 = require("../util/logger");
21
22
  const subscription_1 = require("../util/subscription");
22
23
  function prepareCrowdinRequest(_a) {
@@ -64,7 +65,7 @@ function prepareCrowdinRequest(_a) {
64
65
  return { context, client, subscriptionInfo, logInfo, logError };
65
66
  });
66
67
  }
67
- function handle({ config, optional = false, checkSubscriptionExpiration = true, moduleKey, }) {
68
+ function handle({ config, optional = false, checkSubscriptionExpiration = true, moduleKey, isIntegration = false, }) {
68
69
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
69
70
  var _a, _b;
70
71
  const jwtToken = getToken(req);
@@ -90,6 +91,29 @@ function handle({ config, optional = false, checkSubscriptionExpiration = true,
90
91
  }
91
92
  data.context = (0, api_1.updateCrowdinContext)(req, data.context);
92
93
  }
94
+ if (isIntegration && data.client) {
95
+ const result = yield (0, connection_1.resolveIntegrationAccess)(data.context.clientId);
96
+ if (!result.integrationCredentials) {
97
+ const owners = yield (0, integration_access_denied_1.getIntegrationManagedBy)({
98
+ ownerIds: result.ownerIds,
99
+ crowdinApiClient: data.client,
100
+ clientId: data.context.clientId,
101
+ });
102
+ if (owners.length) {
103
+ data.logInfo('Access denied: no integration access for this project');
104
+ return (0, integration_access_denied_1.renderIntegrationAccessDenied)({
105
+ req,
106
+ res,
107
+ isApiCall: req.isApiCall,
108
+ owners,
109
+ debugLabel: 'crowdin-client',
110
+ });
111
+ }
112
+ }
113
+ else {
114
+ data.context.clientId = result.clientId;
115
+ }
116
+ }
93
117
  req.crowdinContext = data.context;
94
118
  if (data.client) {
95
119
  req.crowdinApiClient = data.client;
@@ -0,0 +1,22 @@
1
+ import Crowdin from '@crowdin/crowdin-api-client';
2
+ import { Response } from 'express';
3
+ import { CrowdinClientRequest } from '../types';
4
+ import { IntegrationRequest } from '../modules/integration/types';
5
+ interface OwnerInfo {
6
+ name: string;
7
+ id: number;
8
+ }
9
+ export declare function getIntegrationManagedBy({ ownerIds, crowdinApiClient, clientId, }: {
10
+ ownerIds: number[];
11
+ crowdinApiClient: Crowdin;
12
+ clientId: string;
13
+ }): Promise<OwnerInfo[]>;
14
+ export declare function renderIntegrationAccessDenied({ req, res, isApiCall, owners, debugLabel, allowLogout, }: {
15
+ req: IntegrationRequest | CrowdinClientRequest;
16
+ res: Response;
17
+ isApiCall?: boolean;
18
+ owners: OwnerInfo[];
19
+ debugLabel: string;
20
+ allowLogout?: boolean;
21
+ }): Response<any, Record<string, any>>;
22
+ export {};
@@ -0,0 +1,107 @@
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
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.getIntegrationManagedBy = getIntegrationManagedBy;
46
+ exports.renderIntegrationAccessDenied = renderIntegrationAccessDenied;
47
+ const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
48
+ const jsx_renderer_1 = require("../util/jsx-renderer");
49
+ const logger_1 = require("../util/logger");
50
+ function getIntegrationManagedBy(_a) {
51
+ return __awaiter(this, arguments, void 0, function* ({ ownerIds, crowdinApiClient, clientId, }) {
52
+ if (!ownerIds.length) {
53
+ return [];
54
+ }
55
+ const projectId = crowdinAppFunctions.getProjectId(clientId);
56
+ let owners = [];
57
+ try {
58
+ owners =
59
+ ownerIds.length > 1
60
+ ? (yield crowdinApiClient.usersApi.listProjectMembers(projectId)).data.filter((member) => ownerIds.includes(member.data.id))
61
+ : [yield crowdinApiClient.usersApi.getProjectMemberPermissions(projectId, ownerIds[0])];
62
+ }
63
+ catch (e) {
64
+ console.warn('Failed to get project members', e);
65
+ return [];
66
+ }
67
+ return owners.map((owner) => {
68
+ const ownerFullName = 'fullName' in owner.data
69
+ ? owner.data.fullName
70
+ : `${owner.data.firstName || ''} ${owner.data.lastName || ''}`.trim();
71
+ return {
72
+ id: owner.data.id,
73
+ name: !!ownerFullName && owner.data.username !== ownerFullName
74
+ ? `${ownerFullName} (${owner.data.username})`
75
+ : owner.data.username,
76
+ };
77
+ });
78
+ });
79
+ }
80
+ function renderIntegrationAccessDenied({ req, res, isApiCall, owners, debugLabel, allowLogout = false, }) {
81
+ const errorOptions = {
82
+ code: 403,
83
+ message: 'Access denied',
84
+ owners: null,
85
+ hideActions: false,
86
+ allowLogout: false,
87
+ };
88
+ if (isApiCall) {
89
+ return res.status(errorOptions.code).json({
90
+ error: {
91
+ message: errorOptions.message,
92
+ },
93
+ });
94
+ }
95
+ if (owners.length) {
96
+ errorOptions.message = 'Looks like you don’t have access';
97
+ errorOptions.hideActions = true;
98
+ errorOptions.owners = owners;
99
+ errorOptions.allowLogout = allowLogout;
100
+ }
101
+ else {
102
+ (0, logger_1.temporaryErrorDebug)(`Access denied: ${debugLabel}`, req);
103
+ }
104
+ const html = (0, jsx_renderer_1.renderJSXOnClient)({ name: 'error', props: errorOptions });
105
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
106
+ return res.send(html);
107
+ }
@@ -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) {
@@ -43,88 +10,57 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
43
10
  };
44
11
  Object.defineProperty(exports, "__esModule", { value: true });
45
12
  exports.default = handle;
46
- const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
47
13
  const users_1 = require("../modules/integration/handlers/users");
48
14
  const storage_1 = require("../storage");
49
15
  const util_1 = require("../util");
50
16
  const connection_1 = require("../util/connection");
51
- const jsx_renderer_1 = require("../util/jsx-renderer");
52
- const logger_1 = require("../util/logger");
17
+ const integration_access_denied_1 = require("./integration-access-denied");
53
18
  function handle({ config, integration, optional = false, isLogout = false, }) {
54
19
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
55
- let clientId = req.crowdinContext.clientId;
56
20
  const isApiCall = req === null || req === void 0 ? void 0 : req.isApiCall;
57
- const { organization, projectId, userId } = crowdinAppFunctions.parseCrowdinId(clientId);
58
- req.logInfo(`Loading integration credentials for client ${clientId}`);
59
- let integrationCredentials = yield (0, storage_1.getStorage)().getIntegrationCredentials(clientId);
60
- let projectIntegrationCredentials = [];
61
- const ownerIds = [];
62
- // check if user has access to integration in settings(managers)
63
- if (!integrationCredentials) {
64
- projectIntegrationCredentials = (yield (0, storage_1.getStorage)().getAllIntegrationCredentials(organization)).filter((item) => {
65
- const { organization: itemOrganization, projectId: itemProjectId } = crowdinAppFunctions.parseCrowdinId(item.id);
66
- return itemOrganization === organization && itemProjectId === projectId;
67
- });
68
- if (projectIntegrationCredentials.length) {
69
- for (const credentials of projectIntegrationCredentials) {
70
- ownerIds.push(crowdinAppFunctions.parseCrowdinId(credentials.id).userId);
71
- if (checkUserAccessToIntegration(credentials, `${userId}`)) {
72
- integrationCredentials = credentials;
73
- clientId = credentials.id;
74
- req.crowdinContext.clientId = clientId;
75
- break;
76
- }
77
- }
78
- }
79
- if (!integrationCredentials && isLogout && projectIntegrationCredentials.length) {
80
- const canForceLogout = yield isCrowdinProjectManager({
21
+ req.logInfo(`Loading integration credentials for client ${req.crowdinContext.clientId}`);
22
+ const { integrationCredentials: resolvedIntegrationCredentials, projectIntegrationCredentials, projectId, clientId: resolvedClientId, ownerIds, } = yield (0, connection_1.resolveIntegrationAccess)(req.crowdinContext.clientId);
23
+ let integrationCredentials = resolvedIntegrationCredentials;
24
+ let clientId = resolvedClientId;
25
+ if (integrationCredentials) {
26
+ req.crowdinContext.clientId = clientId;
27
+ }
28
+ let canForceLogout = null;
29
+ const getCanForceLogout = () => __awaiter(this, void 0, void 0, function* () {
30
+ if (canForceLogout === null) {
31
+ canForceLogout = yield isCrowdinProjectManager({
81
32
  req,
82
33
  projectId,
83
34
  memberId: req.crowdinContext.jwtPayload.context.user_id,
84
35
  });
85
- if (canForceLogout) {
86
- integrationCredentials = projectIntegrationCredentials[0];
87
- clientId = integrationCredentials.id;
88
- req.crowdinContext.clientId = clientId;
89
- req.canForceIntegrationLogout = true;
90
- }
36
+ }
37
+ return canForceLogout;
38
+ });
39
+ if (!integrationCredentials && isLogout && projectIntegrationCredentials.length) {
40
+ if (yield getCanForceLogout()) {
41
+ integrationCredentials = projectIntegrationCredentials[0];
42
+ clientId = integrationCredentials.id;
43
+ req.crowdinContext.clientId = clientId;
44
+ req.canForceIntegrationLogout = true;
91
45
  }
92
46
  }
93
47
  if (!integrationCredentials) {
94
- const owners = yield getIntegrationManagedBy(ownerIds, req);
48
+ const owners = yield (0, integration_access_denied_1.getIntegrationManagedBy)({
49
+ ownerIds,
50
+ crowdinApiClient: req.crowdinApiClient,
51
+ clientId: req.crowdinContext.clientId,
52
+ });
95
53
  if (optional && !owners.length) {
96
54
  return next();
97
55
  }
98
- const errorOptions = {
99
- code: 403,
100
- message: 'Access denied',
101
- owners: null,
102
- hideActions: false,
103
- allowLogout: false,
104
- };
105
- if (isApiCall) {
106
- return res.status(errorOptions.code).json({
107
- error: {
108
- message: errorOptions.message,
109
- },
110
- });
111
- }
112
- if (owners) {
113
- errorOptions.message = 'Looks like you don’t have access';
114
- errorOptions.hideActions = true;
115
- errorOptions.owners = owners;
116
- errorOptions.allowLogout = yield isCrowdinProjectManager({
117
- req,
118
- projectId,
119
- memberId: req.crowdinContext.jwtPayload.context.user_id,
120
- });
121
- }
122
- else {
123
- (0, logger_1.temporaryErrorDebug)('Access denied: integration-credentials', req);
124
- }
125
- const html = (0, jsx_renderer_1.renderJSXOnClient)({ name: 'error', props: errorOptions });
126
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
127
- return res.send(html);
56
+ return (0, integration_access_denied_1.renderIntegrationAccessDenied)({
57
+ req,
58
+ res,
59
+ isApiCall,
60
+ owners,
61
+ debugLabel: 'integration-credentials',
62
+ allowLogout: yield getCanForceLogout(),
63
+ });
128
64
  }
129
65
  try {
130
66
  req.integrationCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
@@ -158,43 +94,6 @@ function handle({ config, integration, optional = false, isLogout = false, }) {
158
94
  next();
159
95
  }));
160
96
  }
161
- function checkUserAccessToIntegration(integrationCredentials, userId) {
162
- if (integrationCredentials === null || integrationCredentials === void 0 ? void 0 : integrationCredentials.managers) {
163
- const managers = JSON.parse(integrationCredentials.managers);
164
- return (managers || []).includes(userId);
165
- }
166
- return false;
167
- }
168
- function getIntegrationManagedBy(ownerIds, req) {
169
- return __awaiter(this, void 0, void 0, function* () {
170
- if (!ownerIds.length) {
171
- return [];
172
- }
173
- const projectId = crowdinAppFunctions.getProjectId(req.crowdinContext.clientId);
174
- let owners = [];
175
- try {
176
- owners =
177
- ownerIds.length > 1
178
- ? (yield req.crowdinApiClient.usersApi.listProjectMembers(projectId)).data.filter((member) => ownerIds.includes(member.data.id))
179
- : [yield req.crowdinApiClient.usersApi.getProjectMemberPermissions(projectId, ownerIds[0])];
180
- }
181
- catch (e) {
182
- console.warn('Failed to get project members', e);
183
- return [];
184
- }
185
- return owners.map((owner) => {
186
- const ownerFullName = 'fullName' in owner.data
187
- ? owner.data.fullName
188
- : `${owner.data.firstName || ''} ${owner.data.lastName || ''}`.trim();
189
- return {
190
- id: owner.data.id,
191
- name: !!ownerFullName && owner.data.username !== ownerFullName
192
- ? `${ownerFullName} (${owner.data.username})`
193
- : owner.data.username,
194
- };
195
- });
196
- });
197
- }
198
97
  function isCrowdinProjectManager(_a) {
199
98
  return __awaiter(this, arguments, void 0, function* ({ req, projectId, memberId, }) {
200
99
  try {
@@ -68,102 +68,119 @@ function register({ config, app }) {
68
68
  optional: false,
69
69
  checkSubscriptionExpiration: true,
70
70
  moduleKey: integrationLogic.key,
71
+ isIntegration: true,
71
72
  }), (0, subscription_info_1.default)(config));
72
73
  app.get('/api/all-jobs', json_response_1.default, (0, crowdin_client_1.default)({
73
74
  config,
74
75
  optional: false,
75
76
  checkSubscriptionExpiration: true,
76
77
  moduleKey: integrationLogic.key,
78
+ isIntegration: true,
77
79
  }), (0, job_list_1.default)());
78
80
  app.get('/api/job-info', json_response_1.default, (0, crowdin_client_1.default)({
79
81
  config,
80
82
  optional: false,
81
83
  checkSubscriptionExpiration: true,
82
84
  moduleKey: integrationLogic.key,
85
+ isIntegration: true,
83
86
  }), (0, job_info_1.default)());
84
87
  app.get('/api/jobs', json_response_1.default, (0, crowdin_client_1.default)({
85
88
  config,
86
89
  optional: false,
87
90
  checkSubscriptionExpiration: true,
88
91
  moduleKey: integrationLogic.key,
92
+ isIntegration: true,
89
93
  }), (0, job_info_deprecated_1.default)(config));
90
94
  app.delete('/api/jobs', json_response_1.default, (0, crowdin_client_1.default)({
91
95
  config,
92
96
  optional: false,
93
97
  checkSubscriptionExpiration: true,
94
98
  moduleKey: integrationLogic.key,
99
+ isIntegration: true,
95
100
  }), (0, job_cancel_1.default)());
96
101
  app.post('/api/settings', (0, crowdin_client_1.default)({
97
102
  config,
98
103
  optional: false,
99
104
  checkSubscriptionExpiration: true,
100
105
  moduleKey: integrationLogic.key,
106
+ isIntegration: true,
101
107
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, settings_save_1.default)(config, integrationLogic));
102
108
  app.post('/api/login', (0, crowdin_client_1.default)({
103
109
  config,
104
110
  optional: false,
105
111
  checkSubscriptionExpiration: false,
106
112
  moduleKey: integrationLogic.key,
113
+ isIntegration: true,
107
114
  }), (0, integration_login_1.default)(config, integrationLogic));
108
115
  app.post('/api/logout', (0, crowdin_client_1.default)({
109
116
  config,
110
117
  optional: false,
111
118
  checkSubscriptionExpiration: false,
112
119
  moduleKey: integrationLogic.key,
120
+ isIntegration: true,
113
121
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic, isLogout: true }), (0, integration_logout_1.default)(config, integrationLogic));
114
122
  app.get('/api/crowdin/files', json_response_1.default, (0, crowdin_client_1.default)({
115
123
  config,
116
124
  optional: false,
117
125
  checkSubscriptionExpiration: true,
118
126
  moduleKey: integrationLogic.key,
127
+ isIntegration: true,
119
128
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, crowdin_files_1.default)(config, integrationLogic));
120
129
  app.get('/api/crowdin/project', json_response_1.default, (0, crowdin_client_1.default)({
121
130
  config,
122
131
  optional: false,
123
132
  checkSubscriptionExpiration: true,
124
133
  moduleKey: integrationLogic.key,
134
+ isIntegration: true,
125
135
  }), (0, crowdin_project_1.default)());
126
136
  app.get('/api/crowdin/file-progress/:fileId', (0, crowdin_client_1.default)({
127
137
  config,
128
138
  optional: false,
129
139
  checkSubscriptionExpiration: true,
130
140
  moduleKey: integrationLogic.key,
141
+ isIntegration: true,
131
142
  }), (0, crowdin_file_progress_1.default)(integrationLogic));
132
143
  app.get('/api/integration/data', json_response_1.default, (0, crowdin_client_1.default)({
133
144
  config,
134
145
  optional: false,
135
146
  checkSubscriptionExpiration: true,
136
147
  moduleKey: integrationLogic.key,
148
+ isIntegration: true,
137
149
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, integration_data_1.default)(integrationLogic));
138
150
  app.post('/api/crowdin/update', json_response_1.default, (0, crowdin_client_1.default)({
139
151
  config,
140
152
  optional: false,
141
153
  checkSubscriptionExpiration: true,
142
154
  moduleKey: integrationLogic.key,
155
+ isIntegration: true,
143
156
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, crowdin_update_1.default)(config, integrationLogic));
144
157
  app.post('/api/crowdin/files-target-languages', json_response_1.default, (0, crowdin_client_1.default)({
145
158
  config,
146
159
  optional: false,
147
160
  checkSubscriptionExpiration: true,
148
161
  moduleKey: integrationLogic.key,
162
+ isIntegration: true,
149
163
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, crowdin_files_target_languages_1.default)(config, integrationLogic));
150
164
  app.post('/api/integration/update', json_response_1.default, (0, crowdin_client_1.default)({
151
165
  config,
152
166
  optional: false,
153
167
  checkSubscriptionExpiration: true,
154
168
  moduleKey: integrationLogic.key,
169
+ isIntegration: true,
155
170
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, integration_update_1.default)(config, integrationLogic));
156
171
  app.get('/api/sync-settings/:provider', json_response_1.default, (0, crowdin_client_1.default)({
157
172
  config,
158
173
  optional: false,
159
174
  checkSubscriptionExpiration: true,
160
175
  moduleKey: integrationLogic.key,
176
+ isIntegration: true,
161
177
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, sync_settings_1.default)());
162
178
  app.post('/api/sync-settings', json_response_1.default, (0, crowdin_client_1.default)({
163
179
  config,
164
180
  optional: false,
165
181
  checkSubscriptionExpiration: true,
166
182
  moduleKey: integrationLogic.key,
183
+ isIntegration: true,
167
184
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, sync_settings_save_1.default)(config, integrationLogic));
168
185
  if (integrationLogic.oauthLogin) {
169
186
  app.get((0, defaults_1.getOauthRoute)(integrationLogic), (0, oauth_login_1.default)(config, integrationLogic));
@@ -172,6 +189,7 @@ function register({ config, app }) {
172
189
  optional: false,
173
190
  checkSubscriptionExpiration: false,
174
191
  moduleKey: integrationLogic.key,
192
+ isIntegration: true,
175
193
  }), (0, oauth_url_1.default)(config, integrationLogic));
176
194
  if (integrationLogic.oauthLogin.mode === 'polling') {
177
195
  app.post('/api/oauth-polling', json_response_1.default, (0, crowdin_client_1.default)({
@@ -179,6 +197,7 @@ function register({ config, app }) {
179
197
  optional: false,
180
198
  checkSubscriptionExpiration: false,
181
199
  moduleKey: integrationLogic.key,
200
+ isIntegration: true,
182
201
  }), (0, oauth_polling_1.default)(config, integrationLogic));
183
202
  }
184
203
  }
@@ -226,17 +245,20 @@ function register({ config, app }) {
226
245
  optional: false,
227
246
  checkSubscriptionExpiration: true,
228
247
  moduleKey: integrationLogic.key,
248
+ isIntegration: true,
229
249
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, user_errors_1.default)());
230
250
  app.get('/api/users', json_response_1.default, (0, crowdin_client_1.default)({
231
251
  config,
232
252
  optional: false,
233
253
  checkSubscriptionExpiration: true,
234
254
  moduleKey: integrationLogic.key,
255
+ isIntegration: true,
235
256
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, users_1.default)());
236
257
  app.post('/api/invite-users', json_response_1.default, (0, crowdin_client_1.default)({
237
258
  config,
238
259
  optional: false,
239
260
  checkSubscriptionExpiration: true,
240
261
  moduleKey: integrationLogic.key,
262
+ isIntegration: true,
241
263
  }), (0, integration_credentials_1.default)({ config, integration: integrationLogic }), (0, invite_users_1.default)());
242
264
  }
@@ -10,4 +10,12 @@ export declare function prepareCrowdinClient({ config, credentials, autoRenew, c
10
10
  client: Crowdin;
11
11
  token: string;
12
12
  }>;
13
+ export interface IntegrationAccessResult {
14
+ integrationCredentials: IntegrationCredentials | null;
15
+ projectIntegrationCredentials: IntegrationCredentials[];
16
+ projectId: number;
17
+ clientId: string;
18
+ ownerIds: number[];
19
+ }
20
+ export declare function resolveIntegrationAccess(clientId: string): Promise<IntegrationAccessResult>;
13
21
  export declare function prepareIntegrationCredentials(config: Config, integration: IntegrationLogic, integrationCredentials: IntegrationCredentials): Promise<any>;
@@ -46,6 +46,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
48
  exports.prepareCrowdinClient = prepareCrowdinClient;
49
+ exports.resolveIntegrationAccess = resolveIntegrationAccess;
49
50
  exports.prepareIntegrationCredentials = prepareIntegrationCredentials;
50
51
  const crowdin_api_client_1 = __importDefault(require("@crowdin/crowdin-api-client"));
51
52
  const crowdin_apps_functions_1 = require("@crowdin/crowdin-apps-functions");
@@ -259,6 +260,38 @@ function prepareCrowdinClient(_a) {
259
260
  };
260
261
  });
261
262
  }
263
+ function resolveIntegrationAccess(clientId) {
264
+ return __awaiter(this, void 0, void 0, function* () {
265
+ const { organization, projectId, userId } = crowdinAppFunctions.parseCrowdinId(clientId);
266
+ let integrationCredentials = yield (0, storage_1.getStorage)().getIntegrationCredentials(clientId);
267
+ const ownerIds = [];
268
+ let projectIntegrationCredentials = [];
269
+ if (!integrationCredentials) {
270
+ projectIntegrationCredentials = (yield (0, storage_1.getStorage)().getAllIntegrationCredentials(organization)).filter((item) => {
271
+ const { organization: itemOrganization, projectId: itemProjectId } = crowdinAppFunctions.parseCrowdinId(item.id);
272
+ return itemOrganization === organization && itemProjectId === projectId;
273
+ });
274
+ for (const credentials of projectIntegrationCredentials) {
275
+ ownerIds.push(crowdinAppFunctions.parseCrowdinId(credentials.id).userId);
276
+ if (credentials.managers) {
277
+ const managers = JSON.parse(credentials.managers) || [];
278
+ if (managers.includes(`${userId}`)) {
279
+ integrationCredentials = credentials;
280
+ clientId = credentials.id;
281
+ break;
282
+ }
283
+ }
284
+ }
285
+ }
286
+ return {
287
+ integrationCredentials: integrationCredentials || null,
288
+ projectIntegrationCredentials,
289
+ projectId,
290
+ clientId,
291
+ ownerIds,
292
+ };
293
+ });
294
+ }
262
295
  function prepareIntegrationCredentials(config, integration, integrationCredentials) {
263
296
  return __awaiter(this, void 0, void 0, function* () {
264
297
  const credentials = JSON.parse((0, _1.decryptData)(config, integrationCredentials.credentials));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "1.5.5",
3
+ "version": "1.6.1",
4
4
  "description": "Module that generates for you all common endpoints for serving standalone Crowdin App",
5
5
  "main": "out/index.js",
6
6
  "types": "out/index.d.ts",