@crowdin/app-project-module 0.12.3 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,6 +16,7 @@ In both options you will need to provide Crowdin App configuration file. Please
16
16
  - `saveMetadata` to save metadata (may be associated with an organization, project, etc)
17
17
  - `getMetadata` to get metadata
18
18
  - `deleteMetadata` to delete metadata (usually useful in `onUninstall` hook)
19
+ - `getUserSettings` to get settings that users manage in the integration module
19
20
  - `establishCrowdinConnection` method that accept jwt token that you may forward from module UI and it will return back Crowdin client instance and the context.
20
21
 
21
22
  ## Status
@@ -73,6 +74,10 @@ const configuration = {
73
74
  imagePath: __dirname + '/' + 'logo.png',
74
75
  integration: {
75
76
  withRootFolder: true,
77
+ withCronSync: {
78
+ crowdin: true,
79
+ integration: true,
80
+ },
76
81
  getIntegrationFiles: async (credentials, appSettings) => {
77
82
  //here you need to fetch files/objects from integration
78
83
  return [
@@ -427,14 +432,14 @@ const configuration = {
427
432
  signaturePatterns: {
428
433
  fileName: '^.+\.xml$'
429
434
  },
430
- parseFile: async (file, req) => {
435
+ parseFile: async (file, req, client, context, projectId) => {
431
436
  const xml = convert.xml2json(file, { compact: true, spaces: 4 });
432
437
  const fileContent = JSON.parse(xml);
433
438
  //parse logic
434
439
  const strings = [];
435
440
  return { strings };
436
441
  },
437
- buildFile: async (file, req, strings) => {
442
+ buildFile: async (file, req, strings, client, context, projectId) => {
438
443
  const xml = convert.xml2json(file, { compact: true, spaces: 4 });
439
444
  const fileContent = JSON.parse(xml);
440
445
  //build logic
@@ -1,4 +1,4 @@
1
1
  /// <reference types="qs" />
2
- import { Request, Response } from 'express';
2
+ import { Response } from 'express';
3
3
  import { Config, CustomFileFormatLogic } from '../../models';
4
- export default function handle(baseConfig: Config, baseUrl: string, folder: string, config: CustomFileFormatLogic): (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;
4
+ export default function handle(baseConfig: Config, baseUrl: string, folder: string, config: CustomFileFormatLogic): (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;
@@ -29,7 +29,7 @@ function storeFile(fileContent, folder) {
29
29
  }
30
30
  }));
31
31
  }
32
- function handleBuildFile(baseUrl, dataFolder, config, file, req) {
32
+ function handleBuildFile(baseUrl, dataFolder, config, file, req, client, context, projectId) {
33
33
  return __awaiter(this, void 0, void 0, function* () {
34
34
  const response = {};
35
35
  if (!req.strings && !req.stringsUrl) {
@@ -42,7 +42,7 @@ function handleBuildFile(baseUrl, dataFolder, config, file, req) {
42
42
  else {
43
43
  strings = (yield axios_1.default.get(req.stringsUrl)).data;
44
44
  }
45
- const res = yield config.buildFile(file, req, strings);
45
+ const res = yield config.buildFile(file, req, strings, client, context, projectId);
46
46
  const contentFileEncoded = Buffer.from(res.contentFile).toString('base64');
47
47
  if (Buffer.byteLength(contentFileEncoded, 'utf8') < MAX_BODY_SIZE) {
48
48
  response.content = contentFileEncoded;
@@ -54,10 +54,10 @@ function handleBuildFile(baseUrl, dataFolder, config, file, req) {
54
54
  return response;
55
55
  });
56
56
  }
57
- function handleParseFile(baseUrl, dataFolder, config, file, req) {
57
+ function handleParseFile(baseUrl, dataFolder, config, file, req, client, context, projectId) {
58
58
  return __awaiter(this, void 0, void 0, function* () {
59
59
  const response = {};
60
- const res = yield config.parseFile(file, req);
60
+ const res = yield config.parseFile(file, req, client, context, projectId);
61
61
  if (res.previewFile) {
62
62
  const previewFileEncoded = Buffer.from(res.previewFile).toString('base64');
63
63
  if (Buffer.byteLength(previewFileEncoded, 'utf8') < MAX_BODY_SIZE) {
@@ -108,10 +108,10 @@ function handle(baseConfig, baseUrl, folder, config) {
108
108
  let response = {};
109
109
  switch (body.jobType) {
110
110
  case models_1.ProcessFileJobType.BUILD_FILE:
111
- response = yield handleBuildFile(baseFilesUrl, folder, config, file, body);
111
+ response = yield handleBuildFile(baseFilesUrl, folder, config, file, body, req.crowdinApiClient, req.crowdinContext, req.crowdinContext.jwtPayload.context.project_id);
112
112
  break;
113
113
  case models_1.ProcessFileJobType.PARSE_FILE:
114
- response = yield handleParseFile(baseFilesUrl, folder, config, file, body);
114
+ response = yield handleParseFile(baseFilesUrl, folder, config, file, body, req.crowdinApiClient, req.crowdinContext, req.crowdinContext.jwtPayload.context.project_id);
115
115
  break;
116
116
  }
117
117
  res.send({ data: response });
package/out/index.js CHANGED
@@ -121,7 +121,7 @@ function addCrowdinEndpoints(app, config) {
121
121
  }
122
122
  }
123
123
  if (config.customFileFormat) {
124
- app.post('/process', (0, process_1.default)(config, config.baseUrl, config.customFileFormat.filesFolder || config.dbFolder, config.customFileFormat));
124
+ app.post('/process', (0, crowdin_client_1.default)(config), (0, process_1.default)(config, config.baseUrl, config.customFileFormat.filesFolder || config.dbFolder, config.customFileFormat));
125
125
  app.get('/file/download', (0, download_1.default)(config, config.customFileFormat.filesFolder || config.dbFolder));
126
126
  }
127
127
  if (config.customMT) {
@@ -184,6 +184,12 @@ function addCrowdinEndpoints(app, config) {
184
184
  }
185
185
  }),
186
186
  deleteMetadata: storage.deleteMetadata,
187
+ getUserSettings: (clientId) => __awaiter(this, void 0, void 0, function* () {
188
+ const integrationCredentials = yield storage.getIntegrationCredentials(clientId);
189
+ if (integrationCredentials === null || integrationCredentials === void 0 ? void 0 : integrationCredentials.config) {
190
+ return JSON.parse(integrationCredentials.config);
191
+ }
192
+ }),
187
193
  establishCrowdinConnection: jwtToken => (0, crowdin_client_1.prepareCrowdinRequest)(jwtToken, config),
188
194
  };
189
195
  }
@@ -13,6 +13,17 @@ exports.prepareCrowdinRequest = void 0;
13
13
  const crowdin_apps_functions_1 = require("@crowdin/crowdin-apps-functions");
14
14
  const storage_1 = require("../storage");
15
15
  const util_1 = require("../util");
16
+ function getToken(req) {
17
+ const tokenJwt = (req.query.tokenJwt || req.query.jwtToken);
18
+ if (tokenJwt) {
19
+ return tokenJwt;
20
+ }
21
+ if (req.headers.authorization) {
22
+ if (req.headers.authorization.startsWith('Bearer ') || req.headers.authorization.startsWith('bearer ')) {
23
+ return req.headers.authorization.substring(7);
24
+ }
25
+ }
26
+ }
16
27
  function prepareCrowdinRequest(jwtToken, config, optional = false) {
17
28
  return __awaiter(this, void 0, void 0, function* () {
18
29
  let context;
@@ -47,7 +58,7 @@ function prepareCrowdinRequest(jwtToken, config, optional = false) {
47
58
  exports.prepareCrowdinRequest = prepareCrowdinRequest;
48
59
  function handle(config, optional = false) {
49
60
  return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
50
- const tokenJwt = (req.query.tokenJwt || req.query.jwtToken);
61
+ const tokenJwt = getToken(req);
51
62
  if (!tokenJwt) {
52
63
  return res.status(403).send({ error: 'Access denied' });
53
64
  }
@@ -363,11 +363,11 @@ export interface CustomFileFormatLogic {
363
363
  /**
364
364
  * Used for initial source file upload, source file update, and translation upload
365
365
  */
366
- parseFile: (fileContent: string | object, req: Omit<ProcessFileRequest, 'jobType' | 'file'>) => Promise<ParseFileResponse>;
366
+ parseFile: (fileContent: string | object, req: Omit<ProcessFileRequest, 'jobType' | 'file'>, client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<ParseFileResponse>;
367
367
  /**
368
368
  * Used for translation download
369
369
  */
370
- buildFile: (fileContent: string | object, req: Omit<ProcessFileRequest, 'jobType' | 'file'>, strings: ProcessFileString[]) => Promise<BuildFileResponse>;
370
+ buildFile: (fileContent: string | object, req: Omit<ProcessFileRequest, 'jobType' | 'file'>, strings: ProcessFileString[], client: Crowdin, context: CrowdinContextInfo, projectId: number) => Promise<BuildFileResponse>;
371
371
  }
372
372
  export interface SignaturePatterns {
373
373
  fileName?: string;
@@ -447,6 +447,10 @@ export interface CrowdinAppUtilities {
447
447
  saveMetadata: (id: string, metadata: any) => Promise<void>;
448
448
  getMetadata: (id: string) => Promise<any | undefined>;
449
449
  deleteMetadata: (id: string) => Promise<void>;
450
+ /**
451
+ * Settings that users manage in the integration module
452
+ */
453
+ getUserSettings: (clientId: string) => Promise<any | undefined>;
450
454
  establishCrowdinConnection: (jwtToken: string) => Promise<{
451
455
  context: CrowdinContextInfo;
452
456
  client?: Crowdin;
package/out/util/index.js CHANGED
@@ -115,10 +115,7 @@ function applyDefaults(config, integration) {
115
115
  integration.getCrowdinFiles = (projectId, client, rootFolder) => __awaiter(this, void 0, void 0, function* () {
116
116
  let allDirectories;
117
117
  if (rootFolder) {
118
- allDirectories = (yield client.sourceFilesApi
119
- .withFetchAll()
120
- // @ts-expect-error: Method overloading
121
- .listProjectDirectories(projectId, {
118
+ allDirectories = (yield client.sourceFilesApi.withFetchAll().listProjectDirectories(projectId, {
122
119
  directoryId: rootFolder.id,
123
120
  recursion: 'true',
124
121
  })).data.map(d => d.data);
@@ -203,6 +200,11 @@ function applyDefaults(config, integration) {
203
200
  ];
204
201
  });
205
202
  }
203
+ if (!integration.checkConnection) {
204
+ integration.checkConnection = (apiCredentials) => __awaiter(this, void 0, void 0, function* () {
205
+ yield integration.getIntegrationFiles(apiCredentials);
206
+ });
207
+ }
206
208
  }
207
209
  exports.applyDefaults = applyDefaults;
208
210
  function prepareCrowdinClient(config, credentials) {
@@ -166,10 +166,10 @@
166
166
  .then((res) => {
167
167
  project = res;
168
168
  appComponent.setCrowdinLanguagesData(project.targetLanguages)
169
- {{#if withCronSync}}
170
- getSyncSettings('crowdin');
171
- {{/if}}
172
169
  })
170
+ {{#if withCronSync}}
171
+ .then(() => getSyncSettings('crowdin'))
172
+ {{/if}}
173
173
  .catch(e => catchRejection(e, 'Can\'t fetch Crowdin data'))
174
174
  .finally(() => (appComponent.setAttribute('is-crowdin-loading', false)));
175
175
  }
@@ -204,11 +204,16 @@
204
204
  }
205
205
 
206
206
  function getSyncSettings(provider) {
207
- const filesComponent = appComponent.querySelector(`#${provider}-files`);
208
207
  checkOrigin()
209
208
  .then(restParams => fetch(`/api/sync-settings/${provider}` + restParams))
210
209
  .then(checkResponse)
211
- .then((res) => filesComponent.addScheduledFiles(res))
210
+ .then((res) => {
211
+ if (provider === 'crowdin') {
212
+ appComponent.setCrowdinScheduleSync(res);
213
+ } else {
214
+ appComponent.setIntegrationScheduleSync(res);
215
+ }
216
+ })
212
217
  .catch(e => catchRejection(e, 'Can\'t fetch file progress'));
213
218
  }
214
219
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdin/app-project-module",
3
- "version": "0.12.3",
3
+ "version": "0.13.0",
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",
@@ -12,7 +12,7 @@
12
12
  "test": "echo \"test not implemented\""
13
13
  },
14
14
  "dependencies": {
15
- "@crowdin/crowdin-apps-functions": "0.0.3",
15
+ "@crowdin/crowdin-apps-functions": "0.1.0",
16
16
  "crypto-js": "^4.0.0",
17
17
  "express": "4.17.1",
18
18
  "express-handlebars": "^5.3.4",