@crowdin/app-project-module 0.17.8 → 0.18.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 +30 -3
- package/out/handlers/custom-file-format/process.js +7 -3
- package/out/handlers/install.js +3 -3
- package/out/handlers/integration-login.js +3 -3
- package/out/handlers/integration-logout.js +1 -1
- package/out/handlers/settings-save.js +1 -1
- package/out/handlers/sync-settings-save.js +3 -3
- package/out/handlers/sync-settings.js +1 -1
- package/out/handlers/uninstall.js +1 -1
- package/out/index.js +9 -9
- package/out/middlewares/crowdin-client.js +1 -1
- package/out/middlewares/integration-credentials.js +1 -1
- package/out/middlewares/ui-module.js +1 -1
- package/out/models/index.d.ts +6 -1
- package/out/storage/index.d.ts +26 -22
- package/out/storage/index.js +29 -308
- package/out/storage/postgre.d.ts +42 -0
- package/out/storage/postgre.js +261 -0
- package/out/storage/sqlite.d.ts +37 -0
- package/out/storage/sqlite.js +297 -0
- package/out/util/connection.js +2 -2
- package/out/util/cron.js +5 -5
- package/out/util/index.js +1 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -27,6 +27,9 @@ In both options you will need to provide Crowdin App configuration file. Please
|
|
|
27
27
|
- [Authorization](#authorization)
|
|
28
28
|
- [Custom login form](#customize-your-app-login-form)
|
|
29
29
|
- [OAuth2 login](#oauth2-support)
|
|
30
|
+
- [Storage](#storage)
|
|
31
|
+
- [SQLite](#sqlite)
|
|
32
|
+
- [PostgreSQL](#postgresql)
|
|
30
33
|
- [Settings window](#settings-window)
|
|
31
34
|
- [Info window](#info-window)
|
|
32
35
|
- [Background tasks](#background-tasks)
|
|
@@ -74,9 +77,9 @@ const configuration = {
|
|
|
74
77
|
dbFolder: __dirname,
|
|
75
78
|
imagePath: __dirname + '/' + 'logo.png',
|
|
76
79
|
crowdinUrls: { // custom urls to override
|
|
77
|
-
// apiUrl: 'https
|
|
78
|
-
// accountUrl: 'https://
|
|
79
|
-
// subscriptionUrl: 'https
|
|
80
|
+
// apiUrl: 'https://<copy_name>.crowdin.dev/api/v2', // 'https://<org_name>.<copy_name>.crowdin.dev/api/v2' for enterprise
|
|
81
|
+
// accountUrl: 'https://accounts.<copy_name>.crowdin.dev/oauth/token', // (default https://accounts.crowdin.com/oauth/token)
|
|
82
|
+
// subscriptionUrl: 'https://<copy_name>.crowdin.dev' // (default https://crowdin.com or https://org.api.crowdin.com)
|
|
80
83
|
},
|
|
81
84
|
projectIntegration: {
|
|
82
85
|
withRootFolder: true,
|
|
@@ -314,6 +317,28 @@ configuration.projectIntegration.oauthLogin = {
|
|
|
314
317
|
|
|
315
318
|
Please refer to jsdoc for more details.
|
|
316
319
|
|
|
320
|
+
## Storage
|
|
321
|
+
|
|
322
|
+
Module can be configured to use following storages:
|
|
323
|
+
|
|
324
|
+
### SQLite
|
|
325
|
+
|
|
326
|
+
```javascript
|
|
327
|
+
//specify folder where sqlite db file will be located
|
|
328
|
+
configuration.dbFolder = __dirname;
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### PostgreSQL
|
|
332
|
+
|
|
333
|
+
```javascript
|
|
334
|
+
configuration.postgreConfig = {
|
|
335
|
+
host: 'localhost',
|
|
336
|
+
user: 'postgres',
|
|
337
|
+
password: 'password',
|
|
338
|
+
database: 'test'
|
|
339
|
+
};
|
|
340
|
+
```
|
|
341
|
+
|
|
317
342
|
## Settings window
|
|
318
343
|
|
|
319
344
|
It is also possible to define settings window for your app where users can customize integration flow.
|
|
@@ -480,6 +505,7 @@ const configuration = {
|
|
|
480
505
|
dbFolder: __dirname,
|
|
481
506
|
imagePath: __dirname + '/' + 'logo.png',
|
|
482
507
|
customFileFormat: {
|
|
508
|
+
filesFolder: __dirname,
|
|
483
509
|
type: 'type-xyz',
|
|
484
510
|
multilingual: false,
|
|
485
511
|
autoUploadTranslations: true, //useful when single language format
|
|
@@ -530,6 +556,7 @@ const configuration = {
|
|
|
530
556
|
dbFolder: __dirname,
|
|
531
557
|
imagePath: __dirname + '/' + 'logo.png',
|
|
532
558
|
customFileFormat: {
|
|
559
|
+
filesFolder: __dirname,
|
|
533
560
|
type: 'type-xyz',
|
|
534
561
|
stringsExport: true,
|
|
535
562
|
extensions: [
|
|
@@ -17,7 +17,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
17
17
|
const path_1 = __importDefault(require("path"));
|
|
18
18
|
const models_1 = require("../../models");
|
|
19
19
|
const util_1 = require("../../util");
|
|
20
|
-
const MAX_BODY_SIZE =
|
|
20
|
+
const MAX_BODY_SIZE = 4.9 * 1024 * 1024; //4.9mb
|
|
21
21
|
function storeFile(fileContent, folder) {
|
|
22
22
|
const fileName = `file${Date.now()}`;
|
|
23
23
|
return new Promise((res, rej) => fs_1.default.writeFile(path_1.default.join(folder, 'custom-file-format', fileName), fileContent, err => {
|
|
@@ -70,9 +70,13 @@ function handleParseFile(baseUrl, dataFolder, config, req, client, context, proj
|
|
|
70
70
|
return { response };
|
|
71
71
|
}
|
|
72
72
|
const res = yield config.parseFile(file, req, client, context, projectId);
|
|
73
|
+
let maxSize = MAX_BODY_SIZE;
|
|
74
|
+
if (res.strings && res.previewFile) {
|
|
75
|
+
maxSize = maxSize / 2;
|
|
76
|
+
}
|
|
73
77
|
if (res.previewFile) {
|
|
74
78
|
const previewFileEncoded = Buffer.from(res.previewFile).toString('base64');
|
|
75
|
-
if (Buffer.byteLength(previewFileEncoded, 'utf8') <
|
|
79
|
+
if (Buffer.byteLength(previewFileEncoded, 'utf8') < maxSize) {
|
|
76
80
|
response.preview = previewFileEncoded;
|
|
77
81
|
}
|
|
78
82
|
else {
|
|
@@ -92,7 +96,7 @@ function handleParseFile(baseUrl, dataFolder, config, req, client, context, proj
|
|
|
92
96
|
});
|
|
93
97
|
}
|
|
94
98
|
const stringsJson = JSON.stringify(strings);
|
|
95
|
-
if (Buffer.byteLength(stringsJson, 'utf8') <
|
|
99
|
+
if (Buffer.byteLength(stringsJson, 'utf8') < maxSize) {
|
|
96
100
|
response.strings = strings;
|
|
97
101
|
}
|
|
98
102
|
else {
|
package/out/handlers/install.js
CHANGED
|
@@ -31,13 +31,13 @@ function handle(config) {
|
|
|
31
31
|
expire: (new Date().getTime() / 1000 + token.expiresIn).toString(),
|
|
32
32
|
type: event.domain ? models_1.AccountType.ENTERPRISE : models_1.AccountType.NORMAL,
|
|
33
33
|
};
|
|
34
|
-
const existingCredentials = yield (0, storage_1.
|
|
34
|
+
const existingCredentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(credentials.id);
|
|
35
35
|
if (!!existingCredentials) {
|
|
36
|
-
yield (0, storage_1.
|
|
36
|
+
yield (0, storage_1.getStorage)().updateCrowdinCredentials(credentials);
|
|
37
37
|
(0, util_1.log)('An existing App has been reinstalled', config.logger);
|
|
38
38
|
}
|
|
39
39
|
else {
|
|
40
|
-
yield (0, storage_1.
|
|
40
|
+
yield (0, storage_1.getStorage)().saveCrowdinCredentials(credentials);
|
|
41
41
|
(0, util_1.log)('A new App has been installed', config.logger);
|
|
42
42
|
}
|
|
43
43
|
res.status(204).end();
|
|
@@ -18,12 +18,12 @@ function handle(config, integration) {
|
|
|
18
18
|
(0, util_1.log)('Checking the integration credentials', config.logger);
|
|
19
19
|
yield integration.checkConnection(req.body.credentials);
|
|
20
20
|
}
|
|
21
|
-
const existing = yield (0, storage_1.
|
|
21
|
+
const existing = yield (0, storage_1.getStorage)().getIntegrationCredentials(req.crowdinContext.clientId);
|
|
22
22
|
if (!!existing) {
|
|
23
23
|
(0, util_1.log)('Deleting old credentials', config.logger);
|
|
24
|
-
yield (0, storage_1.
|
|
24
|
+
yield (0, storage_1.getStorage)().deleteIntegrationCredentials(req.crowdinContext.clientId);
|
|
25
25
|
}
|
|
26
|
-
yield (0, storage_1.
|
|
26
|
+
yield (0, storage_1.getStorage)().saveIntegrationCredentials(req.crowdinContext.clientId, (0, util_1.encryptData)(config, JSON.stringify(req.body.credentials)), req.crowdinContext.crowdinId);
|
|
27
27
|
res.status(204).end();
|
|
28
28
|
}), config.onError);
|
|
29
29
|
}
|
|
@@ -15,7 +15,7 @@ const connection_1 = require("../util/connection");
|
|
|
15
15
|
function handle(config) {
|
|
16
16
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
17
17
|
(0, util_1.log)('Recieved integration logout request', config.logger);
|
|
18
|
-
yield (0, storage_1.
|
|
18
|
+
yield (0, storage_1.getStorage)().deleteIntegrationCredentials(req.crowdinContext.clientId);
|
|
19
19
|
(0, connection_1.clearCache)(req.crowdinContext.crowdinId);
|
|
20
20
|
res.status(204).end();
|
|
21
21
|
}), config.onError);
|
|
@@ -14,7 +14,7 @@ const util_1 = require("../util");
|
|
|
14
14
|
function handle(config) {
|
|
15
15
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
(0, util_1.log)(`Saving settings ${JSON.stringify(req.body.config, null, 2)}`, config.logger);
|
|
17
|
-
yield (0, storage_1.
|
|
17
|
+
yield (0, storage_1.getStorage)().updateIntegrationConfig(req.crowdinContext.clientId, JSON.stringify(req.body.config));
|
|
18
18
|
res.status(204).end();
|
|
19
19
|
}), config.onError);
|
|
20
20
|
}
|
|
@@ -14,14 +14,14 @@ const util_1 = require("../util");
|
|
|
14
14
|
function handle(config) {
|
|
15
15
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
const { files, type, provider } = req.body;
|
|
17
|
-
const existingSettings = yield (0, storage_1.
|
|
17
|
+
const existingSettings = yield (0, storage_1.getStorage)().getSyncSettings(req.crowdinContext.clientId, req.crowdinContext.crowdinId, type, provider);
|
|
18
18
|
if (existingSettings) {
|
|
19
19
|
(0, util_1.log)(`Updating sync settings for type ${type} and provider ${provider} ${JSON.stringify(files, null, 2)}`, config.logger);
|
|
20
|
-
yield (0, storage_1.
|
|
20
|
+
yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(files), req.crowdinContext.clientId, req.crowdinContext.crowdinId, type, provider);
|
|
21
21
|
}
|
|
22
22
|
else {
|
|
23
23
|
(0, util_1.log)(`Saving sync settings for type ${type} and provider ${provider} ${JSON.stringify(files, null, 2)}`, config.logger);
|
|
24
|
-
yield (0, storage_1.
|
|
24
|
+
yield (0, storage_1.getStorage)().saveSyncSettings(JSON.stringify(files), req.crowdinContext.clientId, req.crowdinContext.crowdinId, type, provider);
|
|
25
25
|
}
|
|
26
26
|
res.status(204).end();
|
|
27
27
|
}), config.onError);
|
|
@@ -16,7 +16,7 @@ function handle(config) {
|
|
|
16
16
|
let files = {};
|
|
17
17
|
const provider = req.params.provider;
|
|
18
18
|
(0, util_1.log)(`Loading sync settings for provider ${provider}`, config.logger);
|
|
19
|
-
const syncSettings = yield (0, storage_1.
|
|
19
|
+
const syncSettings = yield (0, storage_1.getStorage)().getSyncSettingsByProvider(req.crowdinContext.clientId, provider);
|
|
20
20
|
if (syncSettings) {
|
|
21
21
|
files = JSON.parse(syncSettings.files) || [];
|
|
22
22
|
}
|
|
@@ -16,7 +16,7 @@ function handle(config) {
|
|
|
16
16
|
const event = req.body;
|
|
17
17
|
(0, util_1.log)(`Recieved uninstall request ${JSON.stringify(event, null, 2)}`, config.logger);
|
|
18
18
|
const organization = (event.domain || event.organizationId).toString();
|
|
19
|
-
yield (0, storage_1.
|
|
19
|
+
yield (0, storage_1.getStorage)().deleteCrowdinCredentials(organization);
|
|
20
20
|
if (config.onUninstall) {
|
|
21
21
|
yield config.onUninstall(organization);
|
|
22
22
|
}
|
package/out/index.js
CHANGED
|
@@ -68,7 +68,7 @@ const defaults_1 = require("./util/defaults");
|
|
|
68
68
|
var models_1 = require("./models");
|
|
69
69
|
Object.defineProperty(exports, "Scope", { enumerable: true, get: function () { return models_1.Scope; } });
|
|
70
70
|
function addCrowdinEndpoints(app, config) {
|
|
71
|
-
storage.
|
|
71
|
+
storage.initialize(config);
|
|
72
72
|
app.use(express_1.default.json({ limit: '50mb' }));
|
|
73
73
|
app.use('/assets', express_1.default.static((0, path_1.join)(__dirname, 'static')));
|
|
74
74
|
app.set('views', (0, path_1.join)(__dirname, 'views'));
|
|
@@ -132,8 +132,8 @@ function addCrowdinEndpoints(app, config) {
|
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
if (config.customFileFormat) {
|
|
135
|
-
app.post('/process', (0, crowdin_client_1.default)(config), (0, process_1.default)(config, config.baseUrl, config.customFileFormat.filesFolder || config.dbFolder, config.customFileFormat));
|
|
136
|
-
app.get('/file/download', (0, download_1.default)(config, config.customFileFormat.filesFolder || config.dbFolder));
|
|
135
|
+
app.post('/process', (0, crowdin_client_1.default)(config), (0, process_1.default)(config, config.baseUrl, config.customFileFormat.filesFolder || config.dbFolder || '/', config.customFileFormat));
|
|
136
|
+
app.get('/file/download', (0, download_1.default)(config, config.customFileFormat.filesFolder || config.dbFolder || '/'));
|
|
137
137
|
}
|
|
138
138
|
if (config.customMT) {
|
|
139
139
|
app.post('/translate', (0, crowdin_client_1.default)(config), (0, translate_1.default)(config, config.customMT));
|
|
@@ -161,19 +161,19 @@ function addCrowdinEndpoints(app, config) {
|
|
|
161
161
|
app.use('/reports', (0, ui_module_1.default)(config), express_1.default.static(config.projectReports.uiPath));
|
|
162
162
|
}
|
|
163
163
|
return {
|
|
164
|
-
getMetadata: storage.getMetadata,
|
|
164
|
+
getMetadata: storage.getStorage().getMetadata,
|
|
165
165
|
saveMetadata: (id, metadata) => __awaiter(this, void 0, void 0, function* () {
|
|
166
|
-
const existing = yield storage.getMetadata(id);
|
|
166
|
+
const existing = yield storage.getStorage().getMetadata(id);
|
|
167
167
|
if (existing) {
|
|
168
|
-
yield storage.updateMetadata(id, metadata);
|
|
168
|
+
yield storage.getStorage().updateMetadata(id, metadata);
|
|
169
169
|
}
|
|
170
170
|
else {
|
|
171
|
-
yield storage.saveMetadata(id, metadata);
|
|
171
|
+
yield storage.getStorage().saveMetadata(id, metadata);
|
|
172
172
|
}
|
|
173
173
|
}),
|
|
174
|
-
deleteMetadata: storage.deleteMetadata,
|
|
174
|
+
deleteMetadata: storage.getStorage().deleteMetadata,
|
|
175
175
|
getUserSettings: (clientId) => __awaiter(this, void 0, void 0, function* () {
|
|
176
|
-
const integrationCredentials = yield storage.getIntegrationCredentials(clientId);
|
|
176
|
+
const integrationCredentials = yield storage.getStorage().getIntegrationCredentials(clientId);
|
|
177
177
|
if (integrationCredentials === null || integrationCredentials === void 0 ? void 0 : integrationCredentials.config) {
|
|
178
178
|
return JSON.parse(integrationCredentials.config);
|
|
179
179
|
}
|
|
@@ -35,7 +35,7 @@ function prepareCrowdinRequest(jwtToken, config, optional = false, checkSubscrip
|
|
|
35
35
|
crowdinId: `${jwtPayload.domain || jwtPayload.context.organization_id}`,
|
|
36
36
|
};
|
|
37
37
|
(0, util_1.log)('Loading crowdin credentials', config.logger);
|
|
38
|
-
const credentials = yield (0, storage_1.
|
|
38
|
+
const credentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(context.crowdinId);
|
|
39
39
|
if (!credentials) {
|
|
40
40
|
if (optional) {
|
|
41
41
|
return { context };
|
|
@@ -16,7 +16,7 @@ function handle(config, integration, optional = false) {
|
|
|
16
16
|
return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
17
17
|
const clientId = req.crowdinContext.clientId;
|
|
18
18
|
(0, util_1.log)(`Loading integration credentials for client ${clientId}`, config.logger);
|
|
19
|
-
const integrationCredentials = yield (0, storage_1.
|
|
19
|
+
const integrationCredentials = yield (0, storage_1.getStorage)().getIntegrationCredentials(clientId);
|
|
20
20
|
if (!integrationCredentials) {
|
|
21
21
|
if (optional) {
|
|
22
22
|
return next();
|
|
@@ -23,7 +23,7 @@ function handle(config) {
|
|
|
23
23
|
const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(tokenJwt, config.clientSecret);
|
|
24
24
|
const id = `${jwtPayload.domain || jwtPayload.context.organization_id}`;
|
|
25
25
|
(0, util_1.log)('Loading crowdin credentials', config.logger);
|
|
26
|
-
const credentials = yield (0, storage_1.
|
|
26
|
+
const credentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(id);
|
|
27
27
|
if (!credentials) {
|
|
28
28
|
throw new Error("Can't find organization by id");
|
|
29
29
|
}
|
package/out/models/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Crowdin, { LanguagesModel, SourceFilesModel, SourceStringsModel } from '@crowdin/crowdin-api-client';
|
|
2
2
|
import { JwtPayload } from '@crowdin/crowdin-apps-functions';
|
|
3
3
|
import { Request } from 'express';
|
|
4
|
+
import { PostgreStorageConfig } from '../storage/postgre';
|
|
4
5
|
export interface Config extends ImagePath {
|
|
5
6
|
/**
|
|
6
7
|
* client id that we received when registering the app
|
|
@@ -45,7 +46,11 @@ export interface Config extends ImagePath {
|
|
|
45
46
|
/**
|
|
46
47
|
* folder where module will create sqlite db file to persist credentials (e.g. {@example __dirname})
|
|
47
48
|
*/
|
|
48
|
-
dbFolder
|
|
49
|
+
dbFolder?: string;
|
|
50
|
+
/**
|
|
51
|
+
* config to configure PostgreSQL as a storage
|
|
52
|
+
*/
|
|
53
|
+
postgreConfig?: PostgreStorageConfig;
|
|
49
54
|
/**
|
|
50
55
|
* integration module logic
|
|
51
56
|
*/
|
package/out/storage/index.d.ts
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
|
-
import { CrowdinCredentials, IntegrationCredentials, IntegrationSyncSettings } from '../models';
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
import { Config, CrowdinCredentials, IntegrationCredentials, IntegrationSyncSettings } from '../models';
|
|
2
|
+
export interface Storage<T> {
|
|
3
|
+
connect(config: T): Promise<void>;
|
|
4
|
+
saveCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
|
|
5
|
+
updateCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
|
|
6
|
+
getCrowdinCredentials(id: string): Promise<CrowdinCredentials | undefined>;
|
|
7
|
+
getAllCrowdinCredentials(): Promise<CrowdinCredentials[]>;
|
|
8
|
+
deleteCrowdinCredentials(id: string): Promise<void>;
|
|
9
|
+
saveIntegrationCredentials(id: string, credentials: any, crowdinId: string): Promise<void>;
|
|
10
|
+
updateIntegrationCredentials(id: string, credentials: any): Promise<void>;
|
|
11
|
+
updateIntegrationConfig(id: string, config: any): Promise<void>;
|
|
12
|
+
getIntegrationCredentials(id: string): Promise<IntegrationCredentials | undefined>;
|
|
13
|
+
getAllIntegrationCredentials(crowdinId: string): Promise<IntegrationCredentials[]>;
|
|
14
|
+
deleteIntegrationCredentials(id: string): Promise<void>;
|
|
15
|
+
saveMetadata(id: string, metadata: any): Promise<void>;
|
|
16
|
+
updateMetadata(id: string, metadata: any): Promise<void>;
|
|
17
|
+
getMetadata(id: string): Promise<any | undefined>;
|
|
18
|
+
deleteMetadata(id: string): Promise<void>;
|
|
19
|
+
getSyncSettingsByProvider(integrationId: string, provider: string): Promise<IntegrationSyncSettings | undefined>;
|
|
20
|
+
getAllSyncSettingsByType(type: string): Promise<IntegrationSyncSettings[]>;
|
|
21
|
+
saveSyncSettings(files: any, integrationId: string, crowdinId: string, type: string, provider: string): Promise<void>;
|
|
22
|
+
updateSyncSettings(files: any, integrationId: string, crowdinId: string, type: string, provider: string): Promise<void>;
|
|
23
|
+
getSyncSettings(integrationId: string, crowdinId: string, type: string, provider: string): Promise<IntegrationSyncSettings | undefined>;
|
|
24
|
+
}
|
|
25
|
+
export declare function initialize(config: Config): Promise<void>;
|
|
26
|
+
export declare function getStorage(): Storage<any>;
|