@crowdin/app-project-module 0.60.2 → 0.61.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/out/app-test/integration/update-crowdin.js +2 -0
- package/out/app-test/integration/update-integration.js +2 -0
- package/out/modules/integration/handlers/crowdin-update.js +2 -0
- package/out/modules/integration/handlers/integration-update.js +2 -0
- package/out/modules/integration/handlers/oauth-login.js +19 -20
- package/out/modules/integration/handlers/sync-settings-save.js +2 -0
- package/out/modules/integration/types.d.ts +2 -2
- package/out/modules/integration/util/cron.js +4 -0
- package/out/modules/integration/util/defaults.js +3 -7
- package/out/modules/integration/util/job.d.ts +4 -1
- package/out/modules/integration/util/job.js +39 -1
- package/out/modules/integration/util/types.d.ts +22 -0
- package/out/storage/index.d.ts +4 -1
- package/out/storage/mysql.d.ts +4 -1
- package/out/storage/mysql.js +44 -0
- package/out/storage/postgre.d.ts +4 -1
- package/out/storage/postgre.js +45 -0
- package/out/storage/sqlite.d.ts +4 -1
- package/out/storage/sqlite.js +38 -0
- package/out/views/main.handlebars +46 -7
- package/package.json +1 -1
|
@@ -106,6 +106,8 @@ const updateCrowdinTest = ({ appConfig, integrationTestConfig, }) => __awaiter(v
|
|
|
106
106
|
},
|
|
107
107
|
update: updateProgressMock,
|
|
108
108
|
type: types_1.JobClientType.MANUAL,
|
|
109
|
+
fetchTranslation: jest.fn(),
|
|
110
|
+
translationUploaded: jest.fn(),
|
|
109
111
|
},
|
|
110
112
|
});
|
|
111
113
|
}, 'Fail to run method updateCrowdin()');
|
|
@@ -63,6 +63,8 @@ const updateIntegrationTest = ({ appConfig, integrationTestConfig, }) => __await
|
|
|
63
63
|
},
|
|
64
64
|
update: updateProgressMock,
|
|
65
65
|
type: types_1.JobClientType.MANUAL,
|
|
66
|
+
fetchTranslation: jest.fn(),
|
|
67
|
+
translationUploaded: jest.fn(),
|
|
66
68
|
},
|
|
67
69
|
});
|
|
68
70
|
}, 'Fail to run method updateIntegration()');
|
|
@@ -40,6 +40,8 @@ function handle(config, integration) {
|
|
|
40
40
|
title: 'Sync files to Crowdin',
|
|
41
41
|
payload: req.body,
|
|
42
42
|
res,
|
|
43
|
+
projectId: projectId,
|
|
44
|
+
client: req.crowdinApiClient,
|
|
43
45
|
jobType: types_1.JobClientType.MANUAL,
|
|
44
46
|
jobCallback: (job) => __awaiter(this, void 0, void 0, function* () {
|
|
45
47
|
var _c;
|
|
@@ -34,6 +34,8 @@ function handle(config, integration) {
|
|
|
34
34
|
title: 'Sync files to ' + config.name,
|
|
35
35
|
payload: req.body,
|
|
36
36
|
res,
|
|
37
|
+
projectId: req.crowdinContext.jwtPayload.context.project_id,
|
|
38
|
+
client: req.crowdinApiClient,
|
|
37
39
|
jobType: types_1.JobClientType.MANUAL,
|
|
38
40
|
jobCallback: (job) => __awaiter(this, void 0, void 0, function* () {
|
|
39
41
|
const result = yield integration.updateIntegration({
|
|
@@ -19,52 +19,51 @@ const logger_1 = require("../../../util/logger");
|
|
|
19
19
|
const storage_1 = require("../../../storage");
|
|
20
20
|
function handle(config, integration) {
|
|
21
21
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
22
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p
|
|
22
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
23
23
|
const message = {
|
|
24
24
|
uid: 'oauth_popup',
|
|
25
25
|
};
|
|
26
26
|
const code = req.query[((_b = (_a = integration.oauthLogin) === null || _a === void 0 ? void 0 : _a.fieldsMapping) === null || _b === void 0 ? void 0 : _b.code) || 'code'];
|
|
27
|
-
const state = ((_c = integration.oauthLogin) === null || _c === void 0 ? void 0 : _c.
|
|
28
|
-
? req.query[((_e = (_d = integration.oauthLogin) === null || _d === void 0 ? void 0 : _d.fieldsMapping) === null || _e === void 0 ? void 0 : _e.state) || 'state']
|
|
29
|
-
: undefined;
|
|
27
|
+
const state = req.query[((_d = (_c = integration.oauthLogin) === null || _c === void 0 ? void 0 : _c.fieldsMapping) === null || _d === void 0 ? void 0 : _d.state) || 'state'];
|
|
30
28
|
(0, logger_1.log)(`Received request from OAuth login callback. Code ${code}`);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
29
|
+
(0, logger_1.log)(`Received request from OAuth login callback. State ${state}`);
|
|
30
|
+
const clientId = Buffer.from(state, 'base64').toString();
|
|
31
|
+
const redirectUri = `${config.baseUrl}${(0, defaults_1.getOauthRoute)(integration)}`;
|
|
34
32
|
try {
|
|
35
33
|
const oauthLogin = integration.oauthLogin;
|
|
36
34
|
let credentials;
|
|
37
35
|
if (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.performGetTokenRequest) {
|
|
38
36
|
(0, logger_1.log)('Performing custom get bearer token request');
|
|
39
|
-
|
|
37
|
+
const loginForm = yield (0, storage_1.getStorage)().getMetadata((0, defaults_1.getOAuthLoginFormId)(clientId));
|
|
38
|
+
credentials = yield oauthLogin.performGetTokenRequest(code, req.query, req.originalUrl, redirectUri, loginForm);
|
|
40
39
|
}
|
|
41
40
|
else {
|
|
42
41
|
const request = {};
|
|
43
42
|
const oauthLogin = integration.oauthLogin;
|
|
44
|
-
request[((
|
|
45
|
-
request[((
|
|
46
|
-
request[((
|
|
47
|
-
request[((
|
|
43
|
+
request[((_e = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _e === void 0 ? void 0 : _e.code) || 'code'] = code;
|
|
44
|
+
request[((_f = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _f === void 0 ? void 0 : _f.clientId) || 'client_id'] = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.clientId;
|
|
45
|
+
request[((_g = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _g === void 0 ? void 0 : _g.clientSecret) || 'client_secret'] = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.clientSecret;
|
|
46
|
+
request[((_h = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _h === void 0 ? void 0 : _h.redirectUri) || 'redirect_uri'] = redirectUri;
|
|
48
47
|
if (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.extraAccessTokenParameters) {
|
|
49
48
|
Object.entries(oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.extraAccessTokenParameters).forEach(([key, value]) => (request[key] = value));
|
|
50
49
|
}
|
|
51
|
-
credentials = (yield axios_1.default.post(((
|
|
50
|
+
credentials = (yield axios_1.default.post(((_j = integration.oauthLogin) === null || _j === void 0 ? void 0 : _j.accessTokenUrl) || '', request, {
|
|
52
51
|
headers: { Accept: 'application/json' },
|
|
53
52
|
})).data;
|
|
54
53
|
}
|
|
55
54
|
const oauthCredentials = { originalUrl: req.originalUrl };
|
|
56
|
-
oauthCredentials.accessToken = credentials[((
|
|
55
|
+
oauthCredentials.accessToken = credentials[((_k = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _k === void 0 ? void 0 : _k.accessToken) || 'access_token'];
|
|
57
56
|
if (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.refresh) {
|
|
58
|
-
oauthCredentials.refreshToken = credentials[((
|
|
57
|
+
oauthCredentials.refreshToken = credentials[((_l = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _l === void 0 ? void 0 : _l.refreshToken) || 'refresh_token'];
|
|
59
58
|
oauthCredentials.expireIn =
|
|
60
|
-
Number(credentials[((
|
|
59
|
+
Number(credentials[((_m = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _m === void 0 ? void 0 : _m.expiresIn) || 'expires_in']) + Date.now() / 1000;
|
|
61
60
|
}
|
|
62
61
|
message.data = oauthCredentials;
|
|
63
|
-
if (((
|
|
64
|
-
yield (0, storage_1.getStorage)().deleteMetadata(
|
|
65
|
-
yield (0, storage_1.getStorage)().saveMetadata(
|
|
62
|
+
if (((_o = integration.oauthLogin) === null || _o === void 0 ? void 0 : _o.mode) === 'polling') {
|
|
63
|
+
yield (0, storage_1.getStorage)().deleteMetadata((0, defaults_1.getOAuthPollingId)(clientId));
|
|
64
|
+
yield (0, storage_1.getStorage)().saveMetadata((0, defaults_1.getOAuthPollingId)(clientId), oauthCredentials);
|
|
66
65
|
}
|
|
67
|
-
return res.render('oauth', { message: JSON.stringify(message), oauthMode: (
|
|
66
|
+
return res.render('oauth', { message: JSON.stringify(message), oauthMode: (_p = integration.oauthLogin) === null || _p === void 0 ? void 0 : _p.mode });
|
|
68
67
|
}
|
|
69
68
|
catch (e) {
|
|
70
69
|
(0, logger_1.logError)(e);
|
|
@@ -33,6 +33,8 @@ function handle(config, integration) {
|
|
|
33
33
|
title: 'Save sync settings',
|
|
34
34
|
payload: req.body,
|
|
35
35
|
res,
|
|
36
|
+
projectId: req.crowdinContext.jwtPayload.context.project_id,
|
|
37
|
+
client: req.crowdinApiClient,
|
|
36
38
|
jobType: types_1.JobClientType.MANUAL,
|
|
37
39
|
jobCallback: () => __awaiter(this, void 0, void 0, function* () {
|
|
38
40
|
if (Array.isArray(expandIntegrationFolders) && expandIntegrationFolders.length) {
|
|
@@ -233,7 +233,7 @@ export interface OAuthLogin {
|
|
|
233
233
|
*/
|
|
234
234
|
expiresIn?: string;
|
|
235
235
|
/**
|
|
236
|
-
* default 'state'
|
|
236
|
+
* default 'state'
|
|
237
237
|
*/
|
|
238
238
|
state?: string;
|
|
239
239
|
};
|
|
@@ -264,7 +264,7 @@ export interface OAuthLogin {
|
|
|
264
264
|
*/
|
|
265
265
|
performGetTokenRequest?: (code: string, query: {
|
|
266
266
|
[key: string]: any;
|
|
267
|
-
}, url: string, loginForm?: any) => Promise<any>;
|
|
267
|
+
}, url: string, redirectUri: string, loginForm?: any) => Promise<any>;
|
|
268
268
|
/**
|
|
269
269
|
* Override to implement request for refreshing token (only if 'refresh' is enabled)
|
|
270
270
|
*/
|
|
@@ -233,6 +233,8 @@ function filesCron({ config, integration, period, }) {
|
|
|
233
233
|
title: `Sync files to ${config.name} [scheduled]`,
|
|
234
234
|
payload: filesToProcess,
|
|
235
235
|
jobType: types_2.JobClientType.CRON,
|
|
236
|
+
projectId: projectId,
|
|
237
|
+
client: crowdinClient,
|
|
236
238
|
jobCallback: (job) => __awaiter(this, void 0, void 0, function* () {
|
|
237
239
|
yield integration.updateIntegration({
|
|
238
240
|
projectId,
|
|
@@ -283,6 +285,8 @@ function filesCron({ config, integration, period, }) {
|
|
|
283
285
|
title: 'Sync files to Crowdin [scheduled]',
|
|
284
286
|
payload: intFiles,
|
|
285
287
|
jobType: types_2.JobClientType.CRON,
|
|
288
|
+
projectId: projectId,
|
|
289
|
+
client: crowdinClient,
|
|
286
290
|
jobCallback: (job) => __awaiter(this, void 0, void 0, function* () {
|
|
287
291
|
yield integration.updateCrowdin({
|
|
288
292
|
projectId,
|
|
@@ -268,9 +268,7 @@ function constructOauthUrl({ config, integration, clientId, loginForm, }) {
|
|
|
268
268
|
return;
|
|
269
269
|
}
|
|
270
270
|
let url = oauth.getAuthorizationUrl(`${config.baseUrl}${getOauthRoute(integration)}`, loginForm);
|
|
271
|
-
|
|
272
|
-
url += `&${((_a = oauth.fieldsMapping) === null || _a === void 0 ? void 0 : _a.state) || 'state'}=${getOAuthPollingId(clientId)}`;
|
|
273
|
-
}
|
|
271
|
+
url += `&${((_a = oauth.fieldsMapping) === null || _a === void 0 ? void 0 : _a.state) || 'state'}=${Buffer.from(clientId).toString('base64')}`;
|
|
274
272
|
return url;
|
|
275
273
|
}
|
|
276
274
|
if (!oauth.authorizationUrl) {
|
|
@@ -279,11 +277,9 @@ function constructOauthUrl({ config, integration, clientId, loginForm, }) {
|
|
|
279
277
|
let url = oauth.authorizationUrl || '';
|
|
280
278
|
url += `?${((_b = oauth.fieldsMapping) === null || _b === void 0 ? void 0 : _b.clientId) || 'client_id'}=${oauth.clientId}`;
|
|
281
279
|
url += `&${((_c = oauth.fieldsMapping) === null || _c === void 0 ? void 0 : _c.redirectUri) || 'redirect_uri'}=${config.baseUrl}${getOauthRoute(integration)}`;
|
|
280
|
+
url += `&${((_d = oauth.fieldsMapping) === null || _d === void 0 ? void 0 : _d.state) || 'state'}=${Buffer.from(clientId).toString('base64')}`;
|
|
282
281
|
if (oauth.scope) {
|
|
283
|
-
url += `&${((
|
|
284
|
-
}
|
|
285
|
-
if (oauth.mode === 'polling') {
|
|
286
|
-
url += `&${((_e = oauth.fieldsMapping) === null || _e === void 0 ? void 0 : _e.state) || 'state'}=${getOAuthPollingId(clientId)}`;
|
|
282
|
+
url += `&${((_e = oauth.fieldsMapping) === null || _e === void 0 ? void 0 : _e.scope) || 'scope'}=${oauth.scope}`;
|
|
287
283
|
}
|
|
288
284
|
if (oauth.extraAutorizationUrlParameters) {
|
|
289
285
|
Object.entries(oauth.extraAutorizationUrlParameters).forEach(([key, value]) => (url += `&${key}=${value}`));
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { JobClient, JobClientType, JobType } from './types';
|
|
2
2
|
import { Response } from 'express';
|
|
3
|
-
|
|
3
|
+
import Crowdin from '@crowdin/crowdin-api-client';
|
|
4
|
+
export declare function runAsJob({ integrationId, crowdinId, type, title, payload, res, projectId, client, jobType, jobCallback, onError, }: {
|
|
4
5
|
integrationId: string;
|
|
5
6
|
crowdinId: string;
|
|
6
7
|
type: JobType;
|
|
7
8
|
title?: string;
|
|
8
9
|
payload?: any;
|
|
9
10
|
res?: Response;
|
|
11
|
+
projectId: number;
|
|
12
|
+
client: Crowdin;
|
|
10
13
|
jobType: JobClientType;
|
|
11
14
|
jobCallback: (arg1: JobClient) => Promise<any>;
|
|
12
15
|
onError?: (e: any) => Promise<void>;
|
|
@@ -19,7 +19,7 @@ const blockingJobs = {
|
|
|
19
19
|
[types_1.JobType.CROWDIN_SYNC_SETTINGS_SAVE]: [types_1.JobType.CROWDIN_SYNC_SETTINGS_SAVE],
|
|
20
20
|
[types_1.JobType.INTEGRATION_SYNC_SETTINGS_SAVE]: [types_1.JobType.INTEGRATION_SYNC_SETTINGS_SAVE],
|
|
21
21
|
};
|
|
22
|
-
function runAsJob({ integrationId, crowdinId, type, title, payload, res, jobType, jobCallback, onError, }) {
|
|
22
|
+
function runAsJob({ integrationId, crowdinId, type, title, payload, res, projectId, client, jobType, jobCallback, onError, }) {
|
|
23
23
|
return __awaiter(this, void 0, void 0, function* () {
|
|
24
24
|
const storage = (0, storage_1.getStorage)();
|
|
25
25
|
const activeJobs = yield storage.getActiveJobs({ integrationId, crowdinId });
|
|
@@ -66,6 +66,44 @@ function runAsJob({ integrationId, crowdinId, type, title, payload, res, jobType
|
|
|
66
66
|
});
|
|
67
67
|
},
|
|
68
68
|
type: jobType,
|
|
69
|
+
fetchTranslation: ({ fileId, languageId }) => __awaiter(this, void 0, void 0, function* () {
|
|
70
|
+
const translationCache = yield storage.getTranslationCache({
|
|
71
|
+
integrationId,
|
|
72
|
+
crowdinId,
|
|
73
|
+
fileId,
|
|
74
|
+
languageId,
|
|
75
|
+
});
|
|
76
|
+
if (!translationCache) {
|
|
77
|
+
yield storage.saveTranslationCache({ integrationId, crowdinId, fileId, languageId });
|
|
78
|
+
}
|
|
79
|
+
let translation = null;
|
|
80
|
+
try {
|
|
81
|
+
(0, logger_1.log)(`Receiving translation for file ${fileId} in language ${languageId}`);
|
|
82
|
+
translation = yield client.translationsApi.buildProjectFileTranslation(projectId, fileId, {
|
|
83
|
+
targetLanguageId: languageId,
|
|
84
|
+
}, (translationCache === null || translationCache === void 0 ? void 0 : translationCache.etag) ? translationCache === null || translationCache === void 0 ? void 0 : translationCache.etag : undefined);
|
|
85
|
+
return translation;
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
(0, logger_1.log)(`Unable to get translation for file ${fileId} in language ${languageId}`);
|
|
89
|
+
}
|
|
90
|
+
return translation;
|
|
91
|
+
}),
|
|
92
|
+
translationUploaded: ({ fileId, languageId, etag }) => __awaiter(this, void 0, void 0, function* () {
|
|
93
|
+
const translationCache = yield storage.getTranslationCache({
|
|
94
|
+
integrationId,
|
|
95
|
+
crowdinId,
|
|
96
|
+
fileId,
|
|
97
|
+
languageId,
|
|
98
|
+
});
|
|
99
|
+
(0, logger_1.log)(`Saving etag translation for file ${fileId} in language ${languageId}`);
|
|
100
|
+
if (!translationCache) {
|
|
101
|
+
yield storage.saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag });
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
yield storage.updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag });
|
|
105
|
+
}
|
|
106
|
+
}),
|
|
69
107
|
};
|
|
70
108
|
try {
|
|
71
109
|
const data = yield jobCallback(job);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import Crowdin, { ProjectsGroupsModel } from '@crowdin/crowdin-api-client';
|
|
2
2
|
import { Config } from '../../../types';
|
|
3
3
|
import { IntegrationLogic, IntegrationSyncSettings } from '../types';
|
|
4
|
+
import { ResponseObject } from '@crowdin/crowdin-api-client/out/core';
|
|
5
|
+
import { TranslationsModel } from '@crowdin/crowdin-api-client/out/translations';
|
|
4
6
|
export declare enum JobType {
|
|
5
7
|
UPDATE_TO_CROWDIN = "updateCrowdin",
|
|
6
8
|
UPDATE_TO_INTEGRATION = "updateIntegration",
|
|
@@ -48,6 +50,8 @@ export type JobClient = {
|
|
|
48
50
|
get: () => Promise<Job | undefined>;
|
|
49
51
|
update: UpdateJobProgress;
|
|
50
52
|
type: JobClientType;
|
|
53
|
+
translationUploaded: SaveUploadedFileTranslation;
|
|
54
|
+
fetchTranslation: FetchTranslation;
|
|
51
55
|
};
|
|
52
56
|
export type UpdateJobProgress = ({ progress, status, info, data, }: Omit<UpdateJobParams, 'id'>) => Promise<{
|
|
53
57
|
isCanceled: boolean;
|
|
@@ -63,3 +67,21 @@ export interface GetAllNewFilesArgs {
|
|
|
63
67
|
integrationSettings: any;
|
|
64
68
|
syncSettings: IntegrationSyncSettings;
|
|
65
69
|
}
|
|
70
|
+
export type SaveUploadedFileTranslation = ({ fileId, languageId, etag, }: {
|
|
71
|
+
fileId: number;
|
|
72
|
+
languageId: string;
|
|
73
|
+
etag: string;
|
|
74
|
+
}) => Promise<void>;
|
|
75
|
+
export type FetchTranslation = ({ fileId, languageId, }: {
|
|
76
|
+
fileId: number;
|
|
77
|
+
languageId: string;
|
|
78
|
+
}) => Promise<ResponseObject<TranslationsModel.BuildProjectFileTranslationResponse> | null>;
|
|
79
|
+
export interface TranslationCache {
|
|
80
|
+
integrationId: string;
|
|
81
|
+
crowdinId: string;
|
|
82
|
+
fileId: number;
|
|
83
|
+
languageId: string;
|
|
84
|
+
etag?: string;
|
|
85
|
+
}
|
|
86
|
+
export type GetTranslationCacheParams = Pick<TranslationCache, 'integrationId' | 'crowdinId' | 'fileId' | 'languageId'>;
|
|
87
|
+
export type UpdateTranslationCacheParams = Pick<TranslationCache, 'integrationId' | 'crowdinId' | 'fileId' | 'languageId' | 'etag'>;
|
package/out/storage/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IntegrationConfig, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings, IntegrationWebhooks, Provider } from '../modules/integration/types';
|
|
2
2
|
import { Config, CrowdinCredentials, UnauthorizedConfig } from '../types';
|
|
3
|
-
import { CreateJobParams, GetActiveJobsParams, GetJobParams, Job, UpdateJobParams } from '../modules/integration/util/types';
|
|
3
|
+
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetTranslationCacheParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams } from '../modules/integration/util/types';
|
|
4
4
|
import { UserErrors } from './types';
|
|
5
5
|
export interface Storage {
|
|
6
6
|
migrate(): Promise<void>;
|
|
@@ -43,6 +43,9 @@ export interface Storage {
|
|
|
43
43
|
getJob(params: GetJobParams): Promise<Job | undefined>;
|
|
44
44
|
getActiveJobs(params: GetActiveJobsParams): Promise<Job[] | undefined>;
|
|
45
45
|
deleteFinishedJobs(): Promise<void>;
|
|
46
|
+
saveTranslationCache(params: TranslationCache): Promise<void>;
|
|
47
|
+
getTranslationCache(params: GetTranslationCacheParams): Promise<TranslationCache | undefined>;
|
|
48
|
+
updateTranslationCache(params: UpdateTranslationCacheParams): Promise<void>;
|
|
46
49
|
}
|
|
47
50
|
export declare function initialize(config: Config | UnauthorizedConfig): Promise<void>;
|
|
48
51
|
export declare function getStorage(): Storage;
|
package/out/storage/mysql.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Storage } from '.';
|
|
2
2
|
import { CrowdinCredentials } from '../types';
|
|
3
|
-
import { CreateJobParams, GetActiveJobsParams, GetJobParams, Job, UpdateJobParams } from '../modules/integration/util/types';
|
|
3
|
+
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetTranslationCacheParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams } from '../modules/integration/util/types';
|
|
4
4
|
import { IntegrationConfig, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings, IntegrationWebhooks } from '../modules/integration/types';
|
|
5
5
|
import { UserErrors } from './types';
|
|
6
6
|
export interface MySQLStorageConfig {
|
|
@@ -60,4 +60,7 @@ export declare class MySQLStorage implements Storage {
|
|
|
60
60
|
getJob({ id }: GetJobParams): Promise<Job | undefined>;
|
|
61
61
|
getActiveJobs({ integrationId, crowdinId }: GetActiveJobsParams): Promise<Job[] | undefined>;
|
|
62
62
|
deleteFinishedJobs(): Promise<void>;
|
|
63
|
+
saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }: TranslationCache): Promise<void>;
|
|
64
|
+
getTranslationCache({ integrationId, crowdinId, fileId, languageId, }: GetTranslationCacheParams): Promise<TranslationCache | undefined>;
|
|
65
|
+
updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }: UpdateTranslationCacheParams): Promise<void>;
|
|
63
66
|
}
|
package/out/storage/mysql.js
CHANGED
|
@@ -166,6 +166,17 @@ class MySQLStorage {
|
|
|
166
166
|
finished_at varchar(255)
|
|
167
167
|
)
|
|
168
168
|
`);
|
|
169
|
+
yield connection.execute(`
|
|
170
|
+
create table if not exists translation_file_cache
|
|
171
|
+
(
|
|
172
|
+
id int auto_increment primary key,
|
|
173
|
+
integration_id varchar(255) not null,
|
|
174
|
+
crowdin_id varchar(255) not null,
|
|
175
|
+
file_id int not null,
|
|
176
|
+
language_id varchar(255) not null,
|
|
177
|
+
etag varchar(255)
|
|
178
|
+
)
|
|
179
|
+
`);
|
|
169
180
|
});
|
|
170
181
|
}
|
|
171
182
|
saveCrowdinCredentials(credentials) {
|
|
@@ -234,6 +245,7 @@ class MySQLStorage {
|
|
|
234
245
|
yield connection.execute('DELETE FROM user_errors WHERE crowdin_id = ?', [id]);
|
|
235
246
|
yield connection.execute('DELETE FROM integration_settings WHERE crowdin_id = ?', [id]);
|
|
236
247
|
yield connection.execute('DELETE FROM job WHERE crowdin_id = ?', [id]);
|
|
248
|
+
yield connection.execute('DELETE FROM translation_file_cache WHERE crowdin_id = ?', [id]);
|
|
237
249
|
}));
|
|
238
250
|
});
|
|
239
251
|
}
|
|
@@ -577,5 +589,37 @@ class MySQLStorage {
|
|
|
577
589
|
yield this.executeQuery((connection) => connection.execute('DELETE FROM job WHERE finished_at is not NULL', []));
|
|
578
590
|
});
|
|
579
591
|
}
|
|
592
|
+
saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }) {
|
|
593
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
594
|
+
yield this.dbPromise;
|
|
595
|
+
yield this.executeQuery((connection) => connection.execute(`
|
|
596
|
+
INSERT INTO translation_file_cache(integration_id, crowdin_id, file_id, language_id, etag)
|
|
597
|
+
VALUES (?, ?, ?, ?, ?)
|
|
598
|
+
`, [integrationId, crowdinId, fileId, languageId, etag]));
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
getTranslationCache({ integrationId, crowdinId, fileId, languageId, }) {
|
|
602
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
603
|
+
yield this.dbPromise;
|
|
604
|
+
return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
|
|
605
|
+
const [rows] = yield connection.execute(`
|
|
606
|
+
SELECT integration_id as integrationId, crowdin_id as crowdin_id, file_id as fileId, language_id as languageId
|
|
607
|
+
FROM translation_file_cache
|
|
608
|
+
WHERE integration_id = ? AND crowdin_id = ? AND file_id = ? AND language_id = ?
|
|
609
|
+
`, [integrationId, crowdinId, fileId, languageId]);
|
|
610
|
+
return (rows || [])[0];
|
|
611
|
+
}));
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }) {
|
|
615
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
616
|
+
yield this.dbPromise;
|
|
617
|
+
yield this.executeQuery((connection) => connection.execute(`
|
|
618
|
+
UPDATE translation_file_cache
|
|
619
|
+
SET etag = ?
|
|
620
|
+
WHERE integration_id = ? AND crowdin_id = ? AND file_id = ? AND language_id = ?
|
|
621
|
+
`, [etag, integrationId, crowdinId, fileId, languageId]));
|
|
622
|
+
});
|
|
623
|
+
}
|
|
580
624
|
}
|
|
581
625
|
exports.MySQLStorage = MySQLStorage;
|
package/out/storage/postgre.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Client } from 'pg';
|
|
|
2
2
|
import { Storage } from '.';
|
|
3
3
|
import { CrowdinCredentials } from '../types';
|
|
4
4
|
import { IntegrationConfig, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings, IntegrationWebhooks } from '../modules/integration/types';
|
|
5
|
-
import { CreateJobParams, GetActiveJobsParams, GetJobParams, Job, UpdateJobParams } from '../modules/integration/util/types';
|
|
5
|
+
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetTranslationCacheParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams } from '../modules/integration/util/types';
|
|
6
6
|
import { UserErrors } from './types';
|
|
7
7
|
export interface PostgreStorageConfig {
|
|
8
8
|
host?: string;
|
|
@@ -66,4 +66,7 @@ export declare class PostgreStorage implements Storage {
|
|
|
66
66
|
getJob({ id }: GetJobParams): Promise<Job | undefined>;
|
|
67
67
|
getActiveJobs({ integrationId, crowdinId }: GetActiveJobsParams): Promise<Job[] | undefined>;
|
|
68
68
|
deleteFinishedJobs(): Promise<void>;
|
|
69
|
+
saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }: TranslationCache): Promise<void>;
|
|
70
|
+
getTranslationCache({ integrationId, crowdinId, fileId, languageId, }: GetTranslationCacheParams): Promise<TranslationCache | undefined>;
|
|
71
|
+
updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }: UpdateTranslationCacheParams): Promise<void>;
|
|
69
72
|
}
|
package/out/storage/postgre.js
CHANGED
|
@@ -183,6 +183,17 @@ class PostgreStorage {
|
|
|
183
183
|
finished_at varchar null
|
|
184
184
|
)
|
|
185
185
|
`);
|
|
186
|
+
yield client.query(`
|
|
187
|
+
create table if not exists translation_file_cache
|
|
188
|
+
(
|
|
189
|
+
id serial primary key,
|
|
190
|
+
integration_id varchar not null,
|
|
191
|
+
crowdin_id varchar not null,
|
|
192
|
+
file_id int not null,
|
|
193
|
+
language_id varchar not null,
|
|
194
|
+
etag varchar
|
|
195
|
+
)
|
|
196
|
+
`);
|
|
186
197
|
});
|
|
187
198
|
}
|
|
188
199
|
saveCrowdinCredentials(credentials) {
|
|
@@ -251,6 +262,7 @@ class PostgreStorage {
|
|
|
251
262
|
yield client.query('DELETE FROM user_errors WHERE crowdin_id = $1', [id]);
|
|
252
263
|
yield client.query('DELETE FROM integration_settings WHERE crowdin_id = $1', [id]);
|
|
253
264
|
yield client.query('DELETE FROM job WHERE crowdin_id = $1', [id]);
|
|
265
|
+
yield client.query('DELETE FROM translation_file_cache WHERE crowdin_id = $1', [id]);
|
|
254
266
|
}));
|
|
255
267
|
});
|
|
256
268
|
}
|
|
@@ -597,5 +609,38 @@ class PostgreStorage {
|
|
|
597
609
|
yield this.executeQuery((client) => client.query(' DELETE FROM job WHERE finished_at is not NULL', []));
|
|
598
610
|
});
|
|
599
611
|
}
|
|
612
|
+
saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }) {
|
|
613
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
614
|
+
yield this.dbPromise;
|
|
615
|
+
yield this.executeQuery((client) => client.query(`
|
|
616
|
+
INSERT
|
|
617
|
+
INTO translation_file_cache(integration_id, crowdin_id, file_id, language_id, etag)
|
|
618
|
+
VALUES ($1, $2, $3, $4, $4)
|
|
619
|
+
`, [integrationId, crowdinId, fileId, languageId, etag]));
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
getTranslationCache({ integrationId, crowdinId, fileId, languageId, }) {
|
|
623
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
624
|
+
yield this.dbPromise;
|
|
625
|
+
return this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
|
|
626
|
+
const res = yield client.query(`
|
|
627
|
+
SELECT integration_id as integrationId, crowdin_id as crowdinId, file_id as fileId, language_id as languageId
|
|
628
|
+
FROM translation_file_cache
|
|
629
|
+
WHERE integration_id = $1 AND crowdin_id = $2 AND file_id = $3 AND language_id = $4
|
|
630
|
+
`, [integrationId, crowdinId, fileId, languageId]);
|
|
631
|
+
return res === null || res === void 0 ? void 0 : res.rows[0];
|
|
632
|
+
}));
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }) {
|
|
636
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
637
|
+
yield this.dbPromise;
|
|
638
|
+
yield this.executeQuery((client) => client.query(`
|
|
639
|
+
UPDATE translation_file_cache
|
|
640
|
+
SET etag = $1
|
|
641
|
+
WHERE integration_id = $2 AND crowdin_id = $3 AND file_id = $4 AND language_id = $5
|
|
642
|
+
`, [etag, integrationId, crowdinId, fileId, languageId]));
|
|
643
|
+
});
|
|
644
|
+
}
|
|
600
645
|
}
|
|
601
646
|
exports.PostgreStorage = PostgreStorage;
|
package/out/storage/sqlite.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Storage } from '.';
|
|
2
2
|
import { CrowdinCredentials } from '../types';
|
|
3
3
|
import { IntegrationConfig, IntegrationCredentials, IntegrationFilesSnapshot, IntegrationSyncSettings, IntegrationWebhooks } from '../modules/integration/types';
|
|
4
|
-
import { CreateJobParams, GetActiveJobsParams, GetJobParams, Job, UpdateJobParams } from '../modules/integration/util/types';
|
|
4
|
+
import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetTranslationCacheParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams } from '../modules/integration/util/types';
|
|
5
5
|
import { UserErrors } from './types';
|
|
6
6
|
export interface SQLiteStorageConfig {
|
|
7
7
|
dbFolder: string;
|
|
@@ -61,4 +61,7 @@ export declare class SQLiteStorage implements Storage {
|
|
|
61
61
|
getJob({ id }: GetJobParams): Promise<Job | undefined>;
|
|
62
62
|
getActiveJobs({ integrationId, crowdinId }: GetActiveJobsParams): Promise<Job[] | undefined>;
|
|
63
63
|
deleteFinishedJobs(): Promise<void>;
|
|
64
|
+
saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag }: TranslationCache): Promise<void>;
|
|
65
|
+
getTranslationCache({ integrationId, crowdinId, fileId, languageId, }: GetTranslationCacheParams): Promise<TranslationCache | undefined>;
|
|
66
|
+
updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }: UpdateTranslationCacheParams): Promise<void>;
|
|
64
67
|
}
|
package/out/storage/sqlite.js
CHANGED
|
@@ -256,6 +256,17 @@ class SQLiteStorage {
|
|
|
256
256
|
updated_at varchar null,
|
|
257
257
|
finished_at varchar null
|
|
258
258
|
);
|
|
259
|
+
`, []);
|
|
260
|
+
yield this._run(`
|
|
261
|
+
create table if not exists translation_file_cache
|
|
262
|
+
(
|
|
263
|
+
id integer not null primary key autoincrement,
|
|
264
|
+
integration_id varchar not null,
|
|
265
|
+
crowdin_id varchar not null,
|
|
266
|
+
file_id integer not null,
|
|
267
|
+
language_id varchar not null,
|
|
268
|
+
etag varchar
|
|
269
|
+
);
|
|
259
270
|
`, []);
|
|
260
271
|
this._res && this._res();
|
|
261
272
|
// TODO: temporary code
|
|
@@ -318,6 +329,7 @@ class SQLiteStorage {
|
|
|
318
329
|
yield this.run('DELETE FROM user_errors WHERE crowdin_id = ?', [id]);
|
|
319
330
|
yield this.run('DELETE FROM integration_settings WHERE crowdin_id = ?', [id]);
|
|
320
331
|
yield this.run('DELETE FROM job WHERE crowdin_id = ?', [id]);
|
|
332
|
+
yield this.run('DELETE FROM translation_file_cache WHERE crowdin_id = ?', [id]);
|
|
321
333
|
});
|
|
322
334
|
}
|
|
323
335
|
saveIntegrationCredentials(id, credentials, crowdinId) {
|
|
@@ -575,5 +587,31 @@ class SQLiteStorage {
|
|
|
575
587
|
yield this.run('DELETE FROM job WHERE finished_at is not NULL', []);
|
|
576
588
|
});
|
|
577
589
|
}
|
|
590
|
+
saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag }) {
|
|
591
|
+
return this.run(`
|
|
592
|
+
INSERT
|
|
593
|
+
INTO translation_file_cache(integration_id, crowdin_id, file_id, language_id, etag)
|
|
594
|
+
VALUES (?, ?, ?, ?, ?)
|
|
595
|
+
`, [integrationId, crowdinId, fileId, languageId, etag]);
|
|
596
|
+
}
|
|
597
|
+
getTranslationCache({ integrationId, crowdinId, fileId, languageId, }) {
|
|
598
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
599
|
+
const row = yield this.get(`
|
|
600
|
+
SELECT integration_id as integrationId, crowdin_id as crowdinId, file_id as fileId, language_id as languageId, etag
|
|
601
|
+
FROM translation_file_cache
|
|
602
|
+
WHERE integration_id = ? AND crowdin_id = ? AND file_id = ? AND language_id = ?
|
|
603
|
+
`, [integrationId, crowdinId, fileId, languageId]);
|
|
604
|
+
if (row) {
|
|
605
|
+
return row;
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }) {
|
|
610
|
+
return this.run(`
|
|
611
|
+
UPDATE translation_file_cache
|
|
612
|
+
SET etag = ?
|
|
613
|
+
WHERE integration_id = ? AND crowdin_id = ? AND file_id = ? AND language_id = ?
|
|
614
|
+
`, [etag, integrationId, crowdinId, fileId, languageId]);
|
|
615
|
+
}
|
|
578
616
|
}
|
|
579
617
|
exports.SQLiteStorage = SQLiteStorage;
|
|
@@ -905,12 +905,48 @@
|
|
|
905
905
|
scheduleModal.close();
|
|
906
906
|
}
|
|
907
907
|
|
|
908
|
-
function openScheduleModal(type) {
|
|
908
|
+
async function openScheduleModal(type) {
|
|
909
909
|
const newFile = scheduleModal.querySelector('#new-files')
|
|
910
910
|
const selectedFiles = scheduleModal.querySelector('#selected-files');
|
|
911
|
+
let newFileStatus = 'unChecked';
|
|
912
|
+
|
|
913
|
+
const integrationSyncFolders = (await document.querySelector('crowdin-simple-integration').getIntegrationScheduleSync(true))
|
|
914
|
+
.filter(elements => elements.node_type === '0');
|
|
915
|
+
|
|
916
|
+
const selectedIntegrationFolders = (await document.getElementById('integration-files').getSelected(true))
|
|
917
|
+
.filter(elements => elements.node_type === '0');
|
|
918
|
+
|
|
919
|
+
for (let i = 0; i < selectedIntegrationFolders.length; i++) {
|
|
920
|
+
const selectedElement = selectedIntegrationFolders[i];
|
|
921
|
+
|
|
922
|
+
const found = integrationSyncFolders.some(integrationElement =>
|
|
923
|
+
integrationElement.id === selectedElement.id
|
|
924
|
+
);
|
|
925
|
+
|
|
926
|
+
if (found) {
|
|
927
|
+
newFileStatus = 'checked';
|
|
928
|
+
} else if (!found && newFileStatus === 'checked') {
|
|
929
|
+
newFileStatus = 'clear-selection';
|
|
930
|
+
break;
|
|
931
|
+
} else {
|
|
932
|
+
newFileStatus = 'unChecked';
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
if (newFileStatus === 'checked') {
|
|
937
|
+
newFile[newFileStatus] = true;
|
|
938
|
+
newFile.value = true;
|
|
939
|
+
newFile.removeAttribute('clear-selection');
|
|
940
|
+
} else if (newFileStatus === 'clear-selection') {
|
|
941
|
+
newFile.checked = false;
|
|
942
|
+
newFile.value = false;
|
|
943
|
+
newFile.setAttribute(newFileStatus, '');
|
|
944
|
+
} else {
|
|
945
|
+
newFile.checked = false;
|
|
946
|
+
newFile.value = false;
|
|
947
|
+
newFile.removeAttribute('clear-selection');
|
|
948
|
+
}
|
|
911
949
|
|
|
912
|
-
newFile.checked = false;
|
|
913
|
-
newFile.value = false;
|
|
914
950
|
selectedFiles.checked = true;
|
|
915
951
|
selectedFiles.value = true;
|
|
916
952
|
scheduleModal.querySelector('#save-schedule-sync').setAttribute('disabled', false);
|
|
@@ -919,11 +955,14 @@
|
|
|
919
955
|
}
|
|
920
956
|
|
|
921
957
|
function onChangeAutoSynchronizationOptions() {
|
|
922
|
-
const newFiles = document.getElementById('new-files')
|
|
958
|
+
const newFiles = document.getElementById('new-files');
|
|
959
|
+
newFiles.removeAttribute('clear-selection');
|
|
960
|
+
|
|
961
|
+
const newFilesStatus = newFiles.checked || false;
|
|
923
962
|
const selectedFiles = document.getElementById('selected-files').checked || false;
|
|
924
963
|
const buttonSaveScheduleSync = document.getElementById('save-schedule-sync');
|
|
925
964
|
|
|
926
|
-
if (
|
|
965
|
+
if (newFilesStatus || selectedFiles) {
|
|
927
966
|
buttonSaveScheduleSync.removeAttribute('disabled');
|
|
928
967
|
} else {
|
|
929
968
|
buttonSaveScheduleSync.setAttribute('disabled', true);
|
|
@@ -953,7 +992,7 @@
|
|
|
953
992
|
syncData = e.detail;
|
|
954
993
|
const isFolder = await hasFolder(e.detail);
|
|
955
994
|
if (isFolder && !newIntegrationFiles) {
|
|
956
|
-
openScheduleModal('integration');
|
|
995
|
+
await openScheduleModal('integration');
|
|
957
996
|
return;
|
|
958
997
|
}
|
|
959
998
|
|
|
@@ -981,7 +1020,7 @@
|
|
|
981
1020
|
syncData = e.detail;
|
|
982
1021
|
const isFolder = await hasFolder(e.detail);
|
|
983
1022
|
if (isFolder && !newCrowdinFiles) {
|
|
984
|
-
openScheduleModal('crowdin');
|
|
1023
|
+
await openScheduleModal('crowdin');
|
|
985
1024
|
return;
|
|
986
1025
|
}
|
|
987
1026
|
|
package/package.json
CHANGED