@crowdin/app-project-module 0.63.2 → 0.65.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.
@@ -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, GetTranslationCacheParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams } from '../modules/integration/util/types';
3
+ import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache } from '../modules/integration/util/types';
4
4
  import { UserErrors } from './types';
5
5
  export interface Storage {
6
6
  migrate(): Promise<void>;
@@ -34,6 +34,7 @@ export interface Storage {
34
34
  getAllUserErrors(crowdinId: string, integrationId?: string): Promise<UserErrors[] | undefined>;
35
35
  saveUserError(action: string, message: string, data: any, createdAt: string, crowdinId: string, integrationId?: string): Promise<void>;
36
36
  deleteUserErrors(date: string, crowdinId: string, integrationId?: string): Promise<void>;
37
+ deleteAllUsersErrorsOlderThan(date: string): Promise<void>;
37
38
  saveIntegrationConfig(integrationId: string, crowdinId: string, config: any): Promise<void>;
38
39
  getAllIntegrationConfigs(crowdinId: string): Promise<IntegrationConfig[]>;
39
40
  getIntegrationConfig(integrationId: string): Promise<IntegrationConfig | undefined>;
@@ -43,8 +44,10 @@ export interface Storage {
43
44
  getJob(params: GetJobParams): Promise<Job | undefined>;
44
45
  getActiveJobs(params: GetActiveJobsParams): Promise<Job[] | undefined>;
45
46
  deleteFinishedJobs(): Promise<void>;
47
+ getAllInProgressJobs(): Promise<Job[] | undefined>;
46
48
  saveTranslationCache(params: TranslationCache): Promise<void>;
47
- getTranslationCache(params: GetTranslationCacheParams): Promise<TranslationCache | undefined>;
49
+ getFileTranslationCache(params: GetFileTranslationCache): Promise<TranslationCache[] | undefined>;
50
+ getFileTranslationCacheByLanguage(params: GetFileTranslationCacheByLanguageParams): Promise<TranslationCache | undefined>;
48
51
  updateTranslationCache(params: UpdateTranslationCacheParams): Promise<void>;
49
52
  }
50
53
  export declare function initialize(config: Config | UnauthorizedConfig): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  import { Storage } from '.';
2
2
  import { CrowdinCredentials } from '../types';
3
- import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetTranslationCacheParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams } from '../modules/integration/util/types';
3
+ import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache } 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 {
@@ -51,16 +51,19 @@ export declare class MySQLStorage implements Storage {
51
51
  getAllUserErrors(crowdinId: string, integrationId?: string): Promise<UserErrors[] | undefined>;
52
52
  saveUserError(action: string, message: string, data: any, createdAt: string, crowdinId: string, integrationId?: string): Promise<void>;
53
53
  deleteUserErrors(createdAt: string, crowdinId: string, integrationId?: string): Promise<void>;
54
+ deleteAllUsersErrorsOlderThan(createdAt: string): Promise<void>;
54
55
  saveIntegrationConfig(integrationId: string, crowdinId: string, config: any): Promise<void>;
55
56
  getAllIntegrationConfigs(crowdinId: string): Promise<IntegrationConfig[]>;
56
57
  getIntegrationConfig(integrationId: string): Promise<IntegrationConfig | undefined>;
57
58
  updateIntegrationConfig(integrationId: string, config: any): Promise<void>;
58
59
  createJob({ integrationId, crowdinId, type, title, payload }: CreateJobParams): Promise<string>;
59
- updateJob({ id, progress, status, info, data }: UpdateJobParams): Promise<void>;
60
+ updateJob({ id, progress, status, info, data, attempt }: UpdateJobParams): Promise<void>;
60
61
  getJob({ id }: GetJobParams): Promise<Job | undefined>;
61
62
  getActiveJobs({ integrationId, crowdinId }: GetActiveJobsParams): Promise<Job[] | undefined>;
62
63
  deleteFinishedJobs(): Promise<void>;
64
+ getAllInProgressJobs(): Promise<Job[] | undefined>;
63
65
  saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }: TranslationCache): Promise<void>;
64
- getTranslationCache({ integrationId, crowdinId, fileId, languageId, }: GetTranslationCacheParams): Promise<TranslationCache | undefined>;
66
+ getFileTranslationCache({ integrationId, crowdinId, fileId, }: GetFileTranslationCache): Promise<TranslationCache[] | undefined>;
67
+ getFileTranslationCacheByLanguage({ integrationId, crowdinId, fileId, languageId, }: GetFileTranslationCacheByLanguageParams): Promise<TranslationCache | undefined>;
65
68
  updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }: UpdateTranslationCacheParams): Promise<void>;
66
69
  }
@@ -161,6 +161,7 @@ class MySQLStorage {
161
161
  payload text,
162
162
  info text,
163
163
  data text,
164
+ attempt int 0,
164
165
  created_at varchar(255) not null,
165
166
  updated_at varchar(255),
166
167
  finished_at varchar(255)
@@ -471,6 +472,12 @@ class MySQLStorage {
471
472
  });
472
473
  });
473
474
  }
475
+ deleteAllUsersErrorsOlderThan(createdAt) {
476
+ return __awaiter(this, void 0, void 0, function* () {
477
+ yield this.dbPromise;
478
+ yield this.executeQuery((connection) => connection.execute('DELETE FROM user_errors WHERE created_at < ?', [createdAt]));
479
+ });
480
+ }
474
481
  saveIntegrationConfig(integrationId, crowdinId, config) {
475
482
  return __awaiter(this, void 0, void 0, function* () {
476
483
  yield this.dbPromise;
@@ -518,7 +525,7 @@ class MySQLStorage {
518
525
  return id;
519
526
  });
520
527
  }
521
- updateJob({ id, progress, status, info, data }) {
528
+ updateJob({ id, progress, status, info, data, attempt }) {
522
529
  return __awaiter(this, void 0, void 0, function* () {
523
530
  const updateFields = ['updated_at'];
524
531
  const updateParams = [Date.now().toString()];
@@ -546,6 +553,10 @@ class MySQLStorage {
546
553
  updateFields.push('info = ?');
547
554
  updateParams.push(info);
548
555
  }
556
+ if (attempt) {
557
+ updateFields.push('attempt = ?');
558
+ updateParams.push(attempt);
559
+ }
549
560
  updateParams.push(id);
550
561
  yield this.dbPromise;
551
562
  yield this.executeQuery((connection) => connection.execute(`
@@ -561,7 +572,7 @@ class MySQLStorage {
561
572
  return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
562
573
  const [rows] = yield connection.execute(`
563
574
  SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status,
564
- title, info, payload, data, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
575
+ title, info, data, attempt, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
565
576
  FROM job
566
577
  WHERE id = ?
567
578
  `, [id]);
@@ -575,7 +586,7 @@ class MySQLStorage {
575
586
  return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
576
587
  const [rows] = yield connection.execute(`
577
588
  SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status,
578
- title, info, payload, data, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
589
+ title, info, data, attempt, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
579
590
  FROM job
580
591
  WHERE integration_id = ? AND crowdin_id = ? AND finished_at is NULL
581
592
  `, [integrationId, crowdinId]);
@@ -589,6 +600,20 @@ class MySQLStorage {
589
600
  yield this.executeQuery((connection) => connection.execute('DELETE FROM job WHERE finished_at is not NULL', []));
590
601
  });
591
602
  }
603
+ getAllInProgressJobs() {
604
+ return __awaiter(this, void 0, void 0, function* () {
605
+ yield this.dbPromise;
606
+ return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
607
+ const [rows] = yield connection.execute(`
608
+ SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status,
609
+ title, info, data, attempt, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
610
+ FROM job
611
+ WHERE status = ? AND finished_at is NULL
612
+ `, [types_1.JobStatus.IN_PROGRESS]);
613
+ return rows || [];
614
+ }));
615
+ });
616
+ }
592
617
  saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }) {
593
618
  return __awaiter(this, void 0, void 0, function* () {
594
619
  yield this.dbPromise;
@@ -598,7 +623,20 @@ class MySQLStorage {
598
623
  `, [integrationId, crowdinId, fileId, languageId, etag]));
599
624
  });
600
625
  }
601
- getTranslationCache({ integrationId, crowdinId, fileId, languageId, }) {
626
+ getFileTranslationCache({ integrationId, crowdinId, fileId, }) {
627
+ return __awaiter(this, void 0, void 0, function* () {
628
+ yield this.dbPromise;
629
+ return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
630
+ const [rows] = yield connection.execute(`
631
+ SELECT integration_id as integrationId, crowdin_id as crowdinId, file_id as fileId, language_id as languageId, etag
632
+ FROM translation_file_cache
633
+ WHERE integration_id = ? AND crowdin_id = ? AND file_id = ?
634
+ `, [integrationId, crowdinId, fileId]);
635
+ return rows || [];
636
+ }));
637
+ });
638
+ }
639
+ getFileTranslationCacheByLanguage({ integrationId, crowdinId, fileId, languageId, }) {
602
640
  return __awaiter(this, void 0, void 0, function* () {
603
641
  yield this.dbPromise;
604
642
  return this.executeQuery((connection) => __awaiter(this, void 0, void 0, function* () {
@@ -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, GetTranslationCacheParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams } from '../modules/integration/util/types';
5
+ import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache } from '../modules/integration/util/types';
6
6
  import { UserErrors } from './types';
7
7
  export interface PostgreStorageConfig {
8
8
  host?: string;
@@ -26,6 +26,7 @@ export declare class PostgreStorage implements Storage {
26
26
  migrate(): Promise<void>;
27
27
  alterTables(client: Client): Promise<void>;
28
28
  addColumns(client: Client, newColumns: string[], tableName: string): Promise<void>;
29
+ addColumn(client: Client, columnName: string, tableName: string, columnType: string): Promise<void>;
29
30
  addTables(client: Client): Promise<void>;
30
31
  saveCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
31
32
  updateCrowdinCredentials(credentials: CrowdinCredentials): Promise<void>;
@@ -57,16 +58,19 @@ export declare class PostgreStorage implements Storage {
57
58
  getAllUserErrors(crowdinId: string, integrationId?: string): Promise<UserErrors[] | undefined>;
58
59
  saveUserError(action: string, message: string, data: any, createdAt: string, crowdinId: string, integrationId?: string): Promise<void>;
59
60
  deleteUserErrors(createdAt: string, crowdinId: string, integrationId?: string): Promise<void>;
61
+ deleteAllUsersErrorsOlderThan(createdAt: string): Promise<void>;
60
62
  saveIntegrationConfig(integrationId: string, crowdinId: string, config: any): Promise<void>;
61
63
  getAllIntegrationConfigs(crowdinId: string): Promise<IntegrationConfig[]>;
62
64
  getIntegrationConfig(integrationId: string): Promise<IntegrationConfig | undefined>;
63
65
  updateIntegrationConfig(integrationId: string, config: any): Promise<void>;
64
66
  createJob({ integrationId, crowdinId, type, payload, title }: CreateJobParams): Promise<string>;
65
- updateJob({ id, progress, status, info, data }: UpdateJobParams): Promise<void>;
67
+ updateJob({ id, progress, status, info, data, attempt }: UpdateJobParams): Promise<void>;
66
68
  getJob({ id }: GetJobParams): Promise<Job | undefined>;
67
69
  getActiveJobs({ integrationId, crowdinId }: GetActiveJobsParams): Promise<Job[] | undefined>;
68
70
  deleteFinishedJobs(): Promise<void>;
71
+ getAllInProgressJobs(): Promise<Job[] | undefined>;
69
72
  saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }: TranslationCache): Promise<void>;
70
- getTranslationCache({ integrationId, crowdinId, fileId, languageId, }: GetTranslationCacheParams): Promise<TranslationCache | undefined>;
73
+ getFileTranslationCache({ integrationId, crowdinId, fileId, }: GetFileTranslationCache): Promise<TranslationCache[] | undefined>;
74
+ getFileTranslationCacheByLanguage({ integrationId, crowdinId, fileId, languageId, }: GetFileTranslationCacheByLanguageParams): Promise<TranslationCache | undefined>;
71
75
  updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }: UpdateTranslationCacheParams): Promise<void>;
72
76
  }
@@ -51,7 +51,7 @@ class PostgreStorage {
51
51
  yield this.executeQuery(this.addTables);
52
52
  this._res && this._res();
53
53
  // TODO: temporary code
54
- yield this.executeQuery(this.alterTables);
54
+ yield this.executeQuery((client) => this.alterTables(client));
55
55
  }
56
56
  catch (e) {
57
57
  console.error(e);
@@ -63,6 +63,7 @@ class PostgreStorage {
63
63
  return __awaiter(this, void 0, void 0, function* () {
64
64
  yield this.addColumns(client, ['crowdin_id'], 'app_metadata');
65
65
  yield this.addColumns(client, ['agent_id'], 'crowdin_credentials');
66
+ yield this.addColumn(client, 'attempt', 'job', 'int default 0');
66
67
  });
67
68
  }
68
69
  addColumns(client, newColumns, tableName) {
@@ -79,6 +80,15 @@ class PostgreStorage {
79
80
  }
80
81
  });
81
82
  }
83
+ addColumn(client, columnName, tableName, columnType) {
84
+ return __awaiter(this, void 0, void 0, function* () {
85
+ const tableInfo = yield client.query('SELECT column_name FROM information_schema.columns WHERE table_name = $1', [tableName]);
86
+ const exists = tableInfo.rows.some((columnInfo) => columnInfo.column_name === columnName);
87
+ if (!exists) {
88
+ yield client.query(`ALTER TABLE ${tableName} ADD COLUMN ${columnName} ${columnType};`);
89
+ }
90
+ });
91
+ }
82
92
  addTables(client) {
83
93
  return __awaiter(this, void 0, void 0, function* () {
84
94
  yield client.query(`
@@ -178,6 +188,7 @@ class PostgreStorage {
178
188
  payload varchar null,
179
189
  info varchar null,
180
190
  data varchar null,
191
+ attempt int default 0,
181
192
  created_at varchar not null,
182
193
  updated_at varchar null,
183
194
  finished_at varchar null
@@ -489,6 +500,14 @@ class PostgreStorage {
489
500
  });
490
501
  });
491
502
  }
503
+ deleteAllUsersErrorsOlderThan(createdAt) {
504
+ return __awaiter(this, void 0, void 0, function* () {
505
+ yield this.dbPromise;
506
+ yield this.executeQuery((client) => {
507
+ return client.query('DELETE FROM user_errors WHERE created_at < $1', [createdAt]);
508
+ });
509
+ });
510
+ }
492
511
  saveIntegrationConfig(integrationId, crowdinId, config) {
493
512
  return __awaiter(this, void 0, void 0, function* () {
494
513
  yield this.dbPromise;
@@ -538,7 +557,7 @@ class PostgreStorage {
538
557
  return id;
539
558
  });
540
559
  }
541
- updateJob({ id, progress, status, info, data }) {
560
+ updateJob({ id, progress, status, info, data, attempt }) {
542
561
  return __awaiter(this, void 0, void 0, function* () {
543
562
  const updateFields = ['updated_at'];
544
563
  const updateParams = [Date.now().toString()];
@@ -566,6 +585,10 @@ class PostgreStorage {
566
585
  updateFields.push('info = $' + updateParams.length.toString());
567
586
  updateParams.push(info);
568
587
  }
588
+ if (attempt) {
589
+ updateFields.push('attempt = $' + updateParams.length.toString());
590
+ updateParams.push(attempt);
591
+ }
569
592
  updateParams.push(id);
570
593
  yield this.dbPromise;
571
594
  yield this.executeQuery((client) => client.query(`
@@ -581,7 +604,7 @@ class PostgreStorage {
581
604
  return this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
582
605
  const res = yield client.query(`
583
606
  SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status,
584
- title, info, payload, data, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
607
+ title, info, data, attempt, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
585
608
  FROM job
586
609
  WHERE id = $1
587
610
  `, [id]);
@@ -595,7 +618,7 @@ class PostgreStorage {
595
618
  return this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
596
619
  const res = yield client.query(`
597
620
  SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status,
598
- title, info, payload, data, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
621
+ title, info, data, attempt, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
599
622
  FROM job
600
623
  WHERE integration_id = $1 AND crowdin_id = $2 AND finished_at is NULL
601
624
  `, [integrationId, crowdinId]);
@@ -609,6 +632,20 @@ class PostgreStorage {
609
632
  yield this.executeQuery((client) => client.query(' DELETE FROM job WHERE finished_at is not NULL', []));
610
633
  });
611
634
  }
635
+ getAllInProgressJobs() {
636
+ return __awaiter(this, void 0, void 0, function* () {
637
+ yield this.dbPromise;
638
+ return this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
639
+ const res = yield client.query(`
640
+ SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status,
641
+ title, info, data, attempt, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
642
+ FROM job
643
+ WHERE status = $1 AND finished_at is NULL
644
+ `, [types_1.JobStatus.IN_PROGRESS]);
645
+ return (res === null || res === void 0 ? void 0 : res.rows) || [];
646
+ }));
647
+ });
648
+ }
612
649
  saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }) {
613
650
  return __awaiter(this, void 0, void 0, function* () {
614
651
  yield this.dbPromise;
@@ -619,7 +656,20 @@ class PostgreStorage {
619
656
  `, [integrationId, crowdinId, fileId, languageId, etag]));
620
657
  });
621
658
  }
622
- getTranslationCache({ integrationId, crowdinId, fileId, languageId, }) {
659
+ getFileTranslationCache({ integrationId, crowdinId, fileId, }) {
660
+ return __awaiter(this, void 0, void 0, function* () {
661
+ yield this.dbPromise;
662
+ return this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
663
+ const res = yield client.query(`
664
+ SELECT integration_id as integrationId, crowdin_id as crowdinId, file_id as fileId, language_id as languageId, etag
665
+ FROM translation_file_cache
666
+ WHERE integration_id = $1 AND crowdin_id = $2 AND file_id = $3
667
+ `, [integrationId, crowdinId, fileId]);
668
+ return (res === null || res === void 0 ? void 0 : res.rows) || [];
669
+ }));
670
+ });
671
+ }
672
+ getFileTranslationCacheByLanguage({ integrationId, crowdinId, fileId, languageId, }) {
623
673
  return __awaiter(this, void 0, void 0, function* () {
624
674
  yield this.dbPromise;
625
675
  return this.executeQuery((client) => __awaiter(this, void 0, void 0, function* () {
@@ -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, GetTranslationCacheParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams } from '../modules/integration/util/types';
4
+ import { CreateJobParams, GetActiveJobsParams, GetJobParams, GetFileTranslationCacheByLanguageParams, Job, TranslationCache, UpdateJobParams, UpdateTranslationCacheParams, GetFileTranslationCache } from '../modules/integration/util/types';
5
5
  import { UserErrors } from './types';
6
6
  export interface SQLiteStorageConfig {
7
7
  dbFolder: string;
@@ -19,6 +19,7 @@ export declare class SQLiteStorage implements Storage {
19
19
  private each;
20
20
  private removeColumns;
21
21
  private addColumns;
22
+ private addColumn;
22
23
  private updateTables;
23
24
  private moveIntegrationSettings;
24
25
  migrate(): Promise<void>;
@@ -52,16 +53,19 @@ export declare class SQLiteStorage implements Storage {
52
53
  getAllUserErrors(crowdinId: string, integrationId?: string): Promise<UserErrors[]>;
53
54
  saveUserError(action: string, message: string, data: any, createdAt: string, crowdinId: string, integrationId?: string): Promise<void>;
54
55
  deleteUserErrors(createAt: string, crowdinId: string, integrationId?: string): Promise<void>;
56
+ deleteAllUsersErrorsOlderThan(createAt: string): Promise<void>;
55
57
  saveIntegrationConfig(integrationId: string, crowdinId: string, config: any): Promise<void>;
56
58
  getAllIntegrationConfigs(crowdinId: string): Promise<IntegrationConfig[]>;
57
59
  getIntegrationConfig(integrationId: string): Promise<IntegrationConfig | undefined>;
58
60
  updateIntegrationConfig(integrationId: string, config: any): Promise<void>;
59
61
  createJob({ integrationId, crowdinId, type, title, payload }: CreateJobParams): Promise<string>;
60
- updateJob({ id, progress, status, info, data }: UpdateJobParams): Promise<void>;
62
+ updateJob({ id, progress, status, info, data, attempt }: UpdateJobParams): Promise<void>;
61
63
  getJob({ id }: GetJobParams): Promise<Job | undefined>;
62
64
  getActiveJobs({ integrationId, crowdinId }: GetActiveJobsParams): Promise<Job[] | undefined>;
63
65
  deleteFinishedJobs(): Promise<void>;
66
+ getAllInProgressJobs(): Promise<Job[] | undefined>;
64
67
  saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag }: TranslationCache): Promise<void>;
65
- getTranslationCache({ integrationId, crowdinId, fileId, languageId, }: GetTranslationCacheParams): Promise<TranslationCache | undefined>;
68
+ getFileTranslationCache({ integrationId, crowdinId, fileId, }: GetFileTranslationCache): Promise<TranslationCache[] | undefined>;
69
+ getFileTranslationCacheByLanguage({ integrationId, crowdinId, fileId, languageId, }: GetFileTranslationCacheByLanguageParams): Promise<TranslationCache | undefined>;
66
70
  updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }: UpdateTranslationCacheParams): Promise<void>;
67
71
  }
@@ -118,10 +118,20 @@ class SQLiteStorage {
118
118
  }
119
119
  });
120
120
  }
121
+ addColumn(tableName, column, defaultValue) {
122
+ return __awaiter(this, void 0, void 0, function* () {
123
+ const tableInfo = yield this.each(`PRAGMA table_info(${tableName});`, []);
124
+ const exists = tableInfo.some((columnInfo) => columnInfo.name === column);
125
+ if (!exists) {
126
+ yield this.run(`ALTER TABLE ${tableName} ADD COLUMN ${column} varchar ${defaultValue};`, []);
127
+ }
128
+ });
129
+ }
121
130
  updateTables() {
122
131
  return __awaiter(this, void 0, void 0, function* () {
123
132
  yield this.addColumns(['app_secret', 'domain', 'user_id', 'agent_id', 'organization_id', 'base_url'], 'crowdin_credentials');
124
133
  yield this.addColumns(['crowdin_id'], 'app_metadata');
134
+ yield this.addColumn('job', 'attempt', 'DEFAULT 0');
125
135
  });
126
136
  }
127
137
  moveIntegrationSettings() {
@@ -252,6 +262,7 @@ class SQLiteStorage {
252
262
  payload varchar null,
253
263
  info varchar null,
254
264
  data varchar null,
265
+ attempt varchar DEFAULT 0,
255
266
  created_at varchar not null,
256
267
  updated_at varchar null,
257
268
  finished_at varchar null
@@ -491,6 +502,11 @@ class SQLiteStorage {
491
502
  return this.run(`DELETE FROM user_errors WHERE created_at < ? AND crowdin_id = ? AND ${whereIntegrationCondition}`, params);
492
503
  });
493
504
  }
505
+ deleteAllUsersErrorsOlderThan(createAt) {
506
+ return __awaiter(this, void 0, void 0, function* () {
507
+ yield this.run('DELETE FROM user_errors where created_at < ?', [createAt]);
508
+ });
509
+ }
494
510
  saveIntegrationConfig(integrationId, crowdinId, config) {
495
511
  return this.run('INSERT INTO integration_settings(integration_id, crowdin_id, config) VALUES (?, ?, ?)', [
496
512
  integrationId,
@@ -525,7 +541,7 @@ class SQLiteStorage {
525
541
  return id;
526
542
  });
527
543
  }
528
- updateJob({ id, progress, status, info, data }) {
544
+ updateJob({ id, progress, status, info, data, attempt }) {
529
545
  const updateFields = ['updated_at = ?'];
530
546
  const updateParams = [Date.now().toString()];
531
547
  if (progress) {
@@ -552,6 +568,10 @@ class SQLiteStorage {
552
568
  updateFields.push('info = ?');
553
569
  updateParams.push(info);
554
570
  }
571
+ if (attempt) {
572
+ updateFields.push('attempt = ?');
573
+ updateParams.push(attempt);
574
+ }
555
575
  updateParams.push(id);
556
576
  const query = `
557
577
  UPDATE job
@@ -564,7 +584,7 @@ class SQLiteStorage {
564
584
  return __awaiter(this, void 0, void 0, function* () {
565
585
  const row = yield this.get(`
566
586
  SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status,
567
- title, info, payload, data, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
587
+ title, info, data, attempt, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
568
588
  FROM job
569
589
  WHERE id = ?
570
590
  `, [id]);
@@ -576,7 +596,7 @@ class SQLiteStorage {
576
596
  getActiveJobs({ integrationId, crowdinId }) {
577
597
  return __awaiter(this, void 0, void 0, function* () {
578
598
  return this.each(`
579
- SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status, title, info, payload, data, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
599
+ SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status, title, info, data, attempt, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
580
600
  FROM job
581
601
  WHERE integration_id = ? AND crowdin_id = ? AND finished_at is NULL
582
602
  `, [integrationId, crowdinId]);
@@ -587,6 +607,15 @@ class SQLiteStorage {
587
607
  yield this.run('DELETE FROM job WHERE finished_at is not NULL', []);
588
608
  });
589
609
  }
610
+ getAllInProgressJobs() {
611
+ return __awaiter(this, void 0, void 0, function* () {
612
+ return this.each(`
613
+ SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status, title, info, data, attempt, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
614
+ FROM job
615
+ WHERE status = ? AND finished_at is NULL
616
+ `, [types_1.JobStatus.IN_PROGRESS]);
617
+ });
618
+ }
590
619
  saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag }) {
591
620
  return this.run(`
592
621
  INSERT
@@ -594,7 +623,16 @@ class SQLiteStorage {
594
623
  VALUES (?, ?, ?, ?, ?)
595
624
  `, [integrationId, crowdinId, fileId, languageId, etag]);
596
625
  }
597
- getTranslationCache({ integrationId, crowdinId, fileId, languageId, }) {
626
+ getFileTranslationCache({ integrationId, crowdinId, fileId, }) {
627
+ return __awaiter(this, void 0, void 0, function* () {
628
+ return this.each(`
629
+ SELECT integration_id as integrationId, crowdin_id as crowdinId, file_id as fileId, language_id as languageId, etag
630
+ FROM translation_file_cache
631
+ WHERE integration_id = ? AND crowdin_id = ? AND file_id = ?
632
+ `, [integrationId, crowdinId, fileId]);
633
+ });
634
+ }
635
+ getFileTranslationCacheByLanguage({ integrationId, crowdinId, fileId, languageId, }) {
598
636
  return __awaiter(this, void 0, void 0, function* () {
599
637
  const row = yield this.get(`
600
638
  SELECT integration_id as integrationId, crowdin_id as crowdinId, file_id as fileId, language_id as languageId, etag
@@ -1,6 +1,6 @@
1
1
  /// <reference types="qs" />
2
2
  import { CrowdinClientRequest, UiModule } from '../types';
3
3
  import { Request, Response } from 'express';
4
- declare function postRequestCredentialsMasker(moduleConfig?: UiModule, credentialsExtractor?: Function): (req: CrowdinClientRequest | Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
5
4
  declare function getRequestCredentialsMasker(moduleConfig?: UiModule): (req: Request | CrowdinClientRequest, res: Response, next: Function) => any;
5
+ declare function postRequestCredentialsMasker(moduleConfig?: UiModule, credentialsExtractor?: Function): (req: CrowdinClientRequest | Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
6
6
  export { getRequestCredentialsMasker, postRequestCredentialsMasker };
@@ -32,8 +32,39 @@ function getMaskableFieldsKeys(moduleConfig) {
32
32
  return (0, lodash_get_1.default)(moduleConfig, `formUiSchema[${fieldKey}]['ui:widget']`) === 'password';
33
33
  });
34
34
  }
35
+ function getRequestCredentialsMasker(moduleConfig) {
36
+ return function (req, res, next) {
37
+ // we can't find "password" fields without ui schema
38
+ if (!moduleConfig || !moduleConfig.formSchema || !moduleConfig.formUiSchema) {
39
+ return next();
40
+ }
41
+ // temporary
42
+ if (!moduleConfig.maskPasswords) {
43
+ return next();
44
+ }
45
+ const maskableFieldsKeys = getMaskableFieldsKeys(moduleConfig);
46
+ if (!maskableFieldsKeys.length) {
47
+ return next();
48
+ }
49
+ const originalSend = res.send;
50
+ res.send = function (body) {
51
+ if (body.formData) {
52
+ maskableFieldsKeys.forEach((fieldKey) => {
53
+ if (!body.formData[fieldKey]) {
54
+ return;
55
+ }
56
+ body.formData[fieldKey] = maskKey(body.formData[fieldKey]);
57
+ });
58
+ }
59
+ return originalSend.apply(res, [body]);
60
+ };
61
+ return next();
62
+ };
63
+ }
64
+ exports.getRequestCredentialsMasker = getRequestCredentialsMasker;
35
65
  function postRequestCredentialsMasker(moduleConfig, credentialsExtractor) {
36
66
  return (0, index_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
67
+ var _a;
37
68
  if (!moduleConfig || !moduleConfig.formSchema || !moduleConfig.formUiSchema) {
38
69
  return next();
39
70
  }
@@ -41,7 +72,7 @@ function postRequestCredentialsMasker(moduleConfig, credentialsExtractor) {
41
72
  if (!moduleConfig.maskPasswords) {
42
73
  return next();
43
74
  }
44
- const fieldsKeysInRequest = Object.keys(req.body.data);
75
+ const fieldsKeysInRequest = Object.keys(((_a = req.body) === null || _a === void 0 ? void 0 : _a.data) || []);
45
76
  let unmaskedFields = {};
46
77
  if (credentialsExtractor) {
47
78
  unmaskedFields = yield credentialsExtractor(req, res);
@@ -66,37 +97,8 @@ function postRequestCredentialsMasker(moduleConfig, credentialsExtractor) {
66
97
  }
67
98
  return acc;
68
99
  }, {}));
69
- next();
100
+ // run getRequestCredentialsMasker to mask fields that can be in response
101
+ return getRequestCredentialsMasker(moduleConfig)(req, res, next);
70
102
  }));
71
103
  }
72
104
  exports.postRequestCredentialsMasker = postRequestCredentialsMasker;
73
- function getRequestCredentialsMasker(moduleConfig) {
74
- return function (req, res, next) {
75
- // we can't find "password" fields without ui schema
76
- if (!moduleConfig || !moduleConfig.formSchema || !moduleConfig.formUiSchema) {
77
- return next();
78
- }
79
- // temporary
80
- if (!moduleConfig.maskPasswords) {
81
- return next();
82
- }
83
- const maskableFieldsKeys = getMaskableFieldsKeys(moduleConfig);
84
- if (!maskableFieldsKeys.length) {
85
- return next();
86
- }
87
- const originalSend = res.send;
88
- res.send = function (body) {
89
- if (body.formData) {
90
- maskableFieldsKeys.forEach((fieldKey) => {
91
- if (!body.formData[fieldKey]) {
92
- return;
93
- }
94
- body.formData[fieldKey] = maskKey(body.formData[fieldKey]);
95
- });
96
- }
97
- return originalSend.apply(res, [body]);
98
- };
99
- return next();
100
- };
101
- }
102
- exports.getRequestCredentialsMasker = getRequestCredentialsMasker;
@@ -10,3 +10,6 @@ export declare function decryptData(config: Config, data: string): string;
10
10
  export declare function executeWithRetry<T>(func: () => Promise<T>, numOfRetries?: number): Promise<T>;
11
11
  export declare function getLogoUrl(moduleConfig?: ImagePath, modulePath?: string): string;
12
12
  export declare function isAuthorizedConfig(config: Config | UnauthorizedConfig): config is Config;
13
+ export declare function hasFormSchema(moduleConfig: any): boolean;
14
+ export declare function isJson(string: string): boolean;
15
+ export declare function getPreviousDate(days: number): Date;
package/out/util/index.js CHANGED
@@ -32,7 +32,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
32
32
  });
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.isAuthorizedConfig = exports.getLogoUrl = exports.executeWithRetry = exports.decryptData = exports.encryptData = exports.runAsyncWrapper = exports.CodeError = void 0;
35
+ exports.getPreviousDate = exports.isJson = exports.hasFormSchema = exports.isAuthorizedConfig = exports.getLogoUrl = exports.executeWithRetry = exports.decryptData = exports.encryptData = exports.runAsyncWrapper = exports.CodeError = void 0;
36
36
  const crypto = __importStar(require("crypto-js"));
37
37
  const storage_1 = require("../storage");
38
38
  const types_1 = require("../types");
@@ -118,3 +118,27 @@ function isAuthorizedConfig(config) {
118
118
  return !!config.clientId && !!config.clientSecret && config.authenticationType !== types_1.AuthenticationType.NONE;
119
119
  }
120
120
  exports.isAuthorizedConfig = isAuthorizedConfig;
121
+ function hasFormSchema(moduleConfig) {
122
+ var _a;
123
+ if (typeof moduleConfig === 'object' && moduleConfig !== null) {
124
+ return moduleConfig.formSchema || ((_a = moduleConfig.settingsUiModule) === null || _a === void 0 ? void 0 : _a.formSchema);
125
+ }
126
+ return false;
127
+ }
128
+ exports.hasFormSchema = hasFormSchema;
129
+ function isJson(string) {
130
+ try {
131
+ JSON.parse(string);
132
+ }
133
+ catch (e) {
134
+ return false;
135
+ }
136
+ return true;
137
+ }
138
+ exports.isJson = isJson;
139
+ function getPreviousDate(days) {
140
+ const date = new Date();
141
+ date.setDate(date.getDate() - days);
142
+ return date;
143
+ }
144
+ exports.getPreviousDate = getPreviousDate;
@@ -224,11 +224,6 @@ function storeUserError({ action, error, crowdinId, clientId, }) {
224
224
  yield (0, storage_1.getStorage)().saveUserError(action, (error === null || error === void 0 ? void 0 : error.message) || JSON.stringify(error, null, 2), JSON.stringify(data), `${Date.now()}`, crowdinId, clientId);
225
225
  });
226
226
  }
227
- function clearOldUserErrors(crowdinId, clientId) {
228
- const date = new Date();
229
- date.setMonth(date.getMonth() - 1); // previous month
230
- (0, storage_1.getStorage)().deleteUserErrors(`${date.getTime()}`, crowdinId, clientId);
231
- }
232
227
  function mergeAppModuleAggregateErrors(errors) {
233
228
  const result = [];
234
229
  const mergedData = {};
@@ -269,7 +264,6 @@ function handleUserError({ action, error, crowdinId, clientId, }) {
269
264
  }
270
265
  else {
271
266
  yield storeUserError({ action, error, crowdinId, clientId });
272
- clearOldUserErrors(crowdinId, clientId);
273
267
  }
274
268
  });
275
269
  }