@adobe/spacecat-shared-data-access 1.15.6 → 1.17.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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [@adobe/spacecat-shared-data-access-v1.17.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v1.16.0...@adobe/spacecat-shared-data-access-v1.17.0) (2024-02-14)
2
+
3
+
4
+ ### Features
5
+
6
+ * get organization by IMS org ID ([#153](https://github.com/adobe/spacecat-shared/issues/153)) ([541e7e7](https://github.com/adobe/spacecat-shared/commit/541e7e721cb21e977b59b19cf53dfb7ba460905f))
7
+
8
+ # [@adobe/spacecat-shared-data-access-v1.16.0](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v1.15.6...@adobe/spacecat-shared-data-access-v1.16.0) (2024-02-14)
9
+
10
+
11
+ ### Features
12
+
13
+ * add configurations data access ([65bdc25](https://github.com/adobe/spacecat-shared/commit/65bdc2581e150cb32eb51d4d2bf03c8172ec2247))
14
+
1
15
  # [@adobe/spacecat-shared-data-access-v1.15.6](https://github.com/adobe/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v1.15.5...@adobe/spacecat-shared-data-access-v1.15.6) (2024-02-12)
2
16
 
3
17
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/spacecat-shared-data-access",
3
- "version": "1.15.6",
3
+ "version": "1.17.0",
4
4
  "description": "Shared modules of the Spacecat Services - Data Access",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
@@ -0,0 +1,33 @@
1
+ /*
2
+ * Copyright 2024 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { createConfiguration } from '../models/configuration.js';
14
+
15
+ /**
16
+ * Data transfer object for Configuration.
17
+ */
18
+ export const ConfigurationDto = {
19
+ /**
20
+ * Converts a DynamoDB item into a Configuration object.
21
+ * @param {object } dynamoItem - DynamoDB item.
22
+ * @returns {Readonly<Configuration>} Configuration object.
23
+ */
24
+ fromDynamoItem: (dynamoItem) => {
25
+ const configurationData = {
26
+ version: dynamoItem.version,
27
+ queues: dynamoItem.queues,
28
+ jobs: dynamoItem.jobs,
29
+ };
30
+
31
+ return createConfiguration(configurationData);
32
+ },
33
+ };
package/src/index.d.ts CHANGED
@@ -315,6 +315,27 @@ export interface Organization {
315
315
  getConfig: () => Config;
316
316
  }
317
317
 
318
+ export interface Configuration {
319
+ /**
320
+ * Retrieves the configuration version.
321
+ * @returns {string} The configuration version.
322
+ */
323
+ getVersion: () => string;
324
+
325
+ /**
326
+ * Retrieves the queues configuration.
327
+ * @returns {object} The queues configuration.
328
+ */
329
+ getQueues: () => object;
330
+
331
+ /**
332
+ * Retrieves the jobs configuration.
333
+ * @returns {Array} The jobs configurations.
334
+ */
335
+ getJobs: () => Array<object>;
336
+
337
+ }
338
+
318
339
  export interface DataAccess {
319
340
  getAuditForSite: (
320
341
  sitedId: string,
@@ -392,6 +413,9 @@ export interface DataAccess {
392
413
  getOrganizationByID: (
393
414
  organizationID: string,
394
415
  ) => Promise<Organization | null>;
416
+ getOrganizationByImsOrgID: (
417
+ imsOrgID: string,
418
+ ) => Promise<Organization | null>;
395
419
  addOrganization: (
396
420
  organizationData: object,
397
421
  ) => Promise<Organization>;
@@ -407,6 +431,10 @@ export interface DataAccess {
407
431
  upsertSiteCandidate: (siteCandidateDate: object) => Promise<SiteCandidate>;
408
432
  siteCandidateExists: (baseURL: string) => Promise<boolean>;
409
433
  updateSiteCandidate: (siteCandidate: SiteCandidate) => Promise<SiteCandidate>;
434
+
435
+ // configuration functions
436
+ getConfiguration: () => Promise<Configuration>
437
+ getConfigurationByVersion: (version: string) => Promise<Configuration>
410
438
  }
411
439
 
412
440
  interface DataAccessConfig {
@@ -415,14 +443,17 @@ interface DataAccessConfig {
415
443
  tableNameOrganizations: string,
416
444
  tableNameSites: string;
417
445
  tableNameSiteCandidates: string;
446
+ tableNameConfigurations: string;
418
447
  indexNameAllSites: string;
419
448
  indexNameAllSitesOrganizations: string,
420
449
  indexNameAllSitesByDeliveryType: string;
421
450
  indexNameAllLatestAuditScores: string;
422
451
  indexNameAllOrganizations: string,
452
+ indexNameAllOrganizationsByImsOrgId: string,
423
453
  pkAllSites: string;
424
454
  pkAllLatestAudits: string;
425
455
  pkAllOrganizations: string;
456
+ pkAllConfigurations: string;
426
457
  }
427
458
 
428
459
  export function createDataAccess(
package/src/index.js CHANGED
@@ -17,14 +17,17 @@ const TABLE_NAME_LATEST_AUDITS = 'spacecat-services-latest-audits-dev';
17
17
  const TABLE_NAME_SITES = 'spacecat-services-sites-dev';
18
18
  const TABLE_NAME_SITE_CANDIDATES = 'spacecat-services-site-candidates-dev';
19
19
  const TABLE_NAME_ORGANIZATIONS = 'spacecat-services-organizations-dev';
20
+ const TABLE_NAME_CONFIGURATIONS = 'spacecat-services-configurations-dev';
20
21
 
21
22
  const INDEX_NAME_ALL_SITES = 'spacecat-services-all-sites-dev';
22
23
  const INDEX_NAME_ALL_ORGANIZATIONS = 'spacecat-services-all-organizations-dev';
24
+ const INDEX_NAME_ALL_ORGANIZATIONS_BY_IMS_ORG_ID = 'spacecat-services-all-organizations-by-ims-org-id-dev';
23
25
  const INDEX_NAME_ALL_SITES_BY_DELIVERY_TYPE = 'spacecat-services-all-sites-by-delivery-type-dev';
24
26
  const INDEX_NAME_ALL_LATEST_AUDIT_SCORES = 'spacecat-services-all-latest-audit-scores-dev';
25
27
  const INDEX_NAME_ALL_SITES_ORGANIZATIONS = 'spacecat-services-all-sites-organizations-dev';
26
28
 
27
29
  const PK_ALL_SITES = 'ALL_SITES';
30
+ const PK_ALL_CONFIGURATIONS = 'ALL_CONFIGURATIONS';
28
31
  const PK_ALL_ORGANIZATIONS = 'ALL_ORGANIZATIONS';
29
32
  const PK_ALL_LATEST_AUDITS = 'ALL_LATEST_AUDITS';
30
33
 
@@ -39,10 +42,13 @@ export default function dataAccessWrapper(fn) {
39
42
  DYNAMO_TABLE_NAME_SITES = TABLE_NAME_SITES,
40
43
  DYNAMO_TABLE_NAME_SITE_CANDIDATES = TABLE_NAME_SITE_CANDIDATES,
41
44
  DYNAMO_TABLE_NAME_ORGANIZATIONS = TABLE_NAME_ORGANIZATIONS,
45
+ DYNAMO_TABLE_NAME_CONFIGURATIONS = TABLE_NAME_CONFIGURATIONS,
42
46
  DYNAMO_INDEX_NAME_ALL_SITES = INDEX_NAME_ALL_SITES,
43
47
  DYNAMO_INDEX_NAME_ALL_SITES_BY_DELIVERY_TYPE = INDEX_NAME_ALL_SITES_BY_DELIVERY_TYPE,
44
48
  DYNAMO_INDEX_NAME_ALL_LATEST_AUDIT_SCORES = INDEX_NAME_ALL_LATEST_AUDIT_SCORES,
45
49
  DYNAMO_INDEX_NAME_ALL_ORGANIZATIONS = INDEX_NAME_ALL_ORGANIZATIONS,
50
+ // eslint-disable-next-line max-len
51
+ DYNAMO_INDEX_NAME_ALL_ORGANIZATIONS_BY_IMS_ORG_ID = INDEX_NAME_ALL_ORGANIZATIONS_BY_IMS_ORG_ID,
46
52
  DYNAMO_INDEX_NAME_ALL_SITES_ORGANIZATIONS = INDEX_NAME_ALL_SITES_ORGANIZATIONS,
47
53
  } = context.env;
48
54
 
@@ -52,14 +58,17 @@ export default function dataAccessWrapper(fn) {
52
58
  tableNameOrganizations: DYNAMO_TABLE_NAME_ORGANIZATIONS,
53
59
  tableNameSites: DYNAMO_TABLE_NAME_SITES,
54
60
  tableNameSiteCandidates: DYNAMO_TABLE_NAME_SITE_CANDIDATES,
61
+ tableNameConfigurations: DYNAMO_TABLE_NAME_CONFIGURATIONS,
55
62
  indexNameAllSites: DYNAMO_INDEX_NAME_ALL_SITES,
56
63
  indexNameAllOrganizations: DYNAMO_INDEX_NAME_ALL_ORGANIZATIONS,
64
+ indexNameAllOrganizationsByImsOrgId: DYNAMO_INDEX_NAME_ALL_ORGANIZATIONS_BY_IMS_ORG_ID,
57
65
  indexNameAllSitesByDeliveryType: DYNAMO_INDEX_NAME_ALL_SITES_BY_DELIVERY_TYPE,
58
66
  indexNameAllLatestAuditScores: DYNAMO_INDEX_NAME_ALL_LATEST_AUDIT_SCORES,
59
67
  indexNameAllSitesOrganizations: DYNAMO_INDEX_NAME_ALL_SITES_ORGANIZATIONS,
60
68
  pkAllSites: PK_ALL_SITES,
61
69
  pkAllOrganizations: PK_ALL_ORGANIZATIONS,
62
70
  pkAllLatestAudits: PK_ALL_LATEST_AUDITS,
71
+ pkAllConfigurations: PK_ALL_CONFIGURATIONS,
63
72
  }, log);
64
73
  }
65
74
 
@@ -0,0 +1,49 @@
1
+ /*
2
+ * Copyright 2024 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import Joi from 'joi';
14
+
15
+ const Configuration = (data = {}) => {
16
+ const self = { ...data };
17
+ self.getJobs = () => self.jobs;
18
+ self.getVersion = () => self.version;
19
+ self.getQueues = () => self.queues;
20
+
21
+ return Object.freeze(self);
22
+ };
23
+
24
+ export const checkConfiguration = (configuration) => {
25
+ const schema = Joi.object({
26
+ version: Joi.string().required(),
27
+ queues: Joi.object().required(),
28
+ jobs: Joi.array().required(),
29
+ }).unknown(true);
30
+ const { error, value } = schema.validate(configuration);
31
+
32
+ if (error) {
33
+ throw new Error(`Configuration validation error: ${error.message}`);
34
+ }
35
+
36
+ return value; // Validated and sanitized configuration
37
+ };
38
+
39
+ /**
40
+ * Creates a new Configuration.
41
+ *
42
+ * @param {object} data - configuration data
43
+ * @returns {Readonly<Configuration>} configuration - new configuration
44
+ */
45
+ export const createConfiguration = (data) => {
46
+ const value = checkConfiguration(data);
47
+ const newState = { ...value };
48
+ return Configuration(newState);
49
+ };
@@ -92,10 +92,15 @@ export const createOrganization = (data) => {
92
92
  if (!isObject(newState.config)) {
93
93
  newState.config = { ...DEFAULT_CONFIG };
94
94
  }
95
+
95
96
  if (!hasText(newState.name)) {
96
97
  throw new Error('Org name must be provided');
97
98
  }
98
99
 
100
+ if (!hasText(newState.imsOrgId)) {
101
+ newState.imsOrgId = DEFAULT_ORGANIZATION_ID;
102
+ }
103
+
99
104
  newState.config = Config(newState.config);
100
105
 
101
106
  return Organization(newState);
@@ -0,0 +1,63 @@
1
+ /*
2
+ * Copyright 2024 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+
13
+ import { isObject } from '@adobe/spacecat-shared-utils';
14
+
15
+ import { ConfigurationDto } from '../../dto/configuration.js';
16
+
17
+ /**
18
+ * Retrieves configuration with latest version.
19
+ *
20
+ * @param {DynamoDbClient} dynamoClient - The DynamoDB client.
21
+ * @param {DataAccessConfig} config - The data access config.
22
+ * @returns {Promise<Readonly<Configuration>>} A promise that resolves to the configuration
23
+ * object if found, otherwise null.
24
+ */
25
+ export const getConfiguration = async (
26
+ dynamoClient,
27
+ config,
28
+ ) => {
29
+ const dynamoItems = await dynamoClient.query({
30
+ TableName: config.tableNameConfigurations,
31
+ KeyConditionExpression: 'PK = :pk',
32
+ ExpressionAttributeValues: {
33
+ ':pk': config.pkAllConfigurations,
34
+ },
35
+ Limit: 1,
36
+ ScanIndexForward: false, // Sorts ascending if true, descending if false
37
+ });
38
+
39
+ if (dynamoItems.length === 0) return null;
40
+ return ConfigurationDto.fromDynamoItem(dynamoItems[0]);
41
+ };
42
+
43
+ /**
44
+ * Retrieves a site by its version.
45
+ *
46
+ * @param {DynamoDbClient} dynamoClient - The DynamoDB client.
47
+ * @param {DataAccessConfig} config - The data access config.
48
+ * @param {string} version - The version of the configuration to retrieve.
49
+ * @returns {Promise<Readonly<Configuration>|null>} A promise that resolves to the configuration
50
+ * object if found, otherwise null.
51
+ */
52
+ export const getConfigurationByVersion = async (
53
+ dynamoClient,
54
+ config,
55
+ version,
56
+ ) => {
57
+ const dynamoItem = await dynamoClient.getItem(config.tableNameConfigurations, {
58
+ PK: config.pkAllConfigurations,
59
+ version,
60
+ });
61
+
62
+ return isObject(dynamoItem) ? ConfigurationDto.fromDynamoItem(dynamoItem) : null;
63
+ };
@@ -0,0 +1,24 @@
1
+ /*
2
+ * Copyright 2024 Adobe. All rights reserved.
3
+ * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License. You may obtain a copy
5
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ *
7
+ * Unless required by applicable law or agreed to in writing, software distributed under
8
+ * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9
+ * OF ANY KIND, either express or implied. See the License for the specific language
10
+ * governing permissions and limitations under the License.
11
+ */
12
+ import { getConfiguration, getConfigurationByVersion } from './accessPatterns.js';
13
+
14
+ export const configurationFunctions = (dynamoClient, config) => ({
15
+ getConfiguration: () => getConfiguration(
16
+ dynamoClient,
17
+ config,
18
+ ),
19
+ getConfigurationByVersion: (version) => getConfigurationByVersion(
20
+ dynamoClient,
21
+ config,
22
+ version,
23
+ ),
24
+ });
@@ -15,6 +15,7 @@ import { auditFunctions } from './audits/index.js';
15
15
  import { siteFunctions } from './sites/index.js';
16
16
  import { siteCandidateFunctions } from './site-candidates/index.js';
17
17
  import { organizationFunctions } from './organizations/index.js';
18
+ import { configurationFunctions } from './configurations/index.js';
18
19
 
19
20
  /**
20
21
  * Creates a data access object.
@@ -22,7 +23,8 @@ import { organizationFunctions } from './organizations/index.js';
22
23
  * @param {{pkAllSites: string, pkAllLatestAudits: string, indexNameAllLatestAuditScores: string,
23
24
  * tableNameAudits: string,tableNameLatestAudits: string, indexNameAllSitesOrganizations: string,
24
25
  * tableNameSites: string, tableNameOrganizations: string, indexNameAllSites: string,
25
- * indexNameAllOrganizations: string, pkAllOrganizations: string}} config configuration
26
+ * indexNameAllOrganizations: string, indexNameAllOrganizationsByImsOrgId: string,
27
+ * pkAllOrganizations: string}} config configuration
26
28
  * @param {Logger} log logger
27
29
  * @returns {object} data access object
28
30
  */
@@ -33,11 +35,13 @@ export const createDataAccess = (config, log = console) => {
33
35
  const siteFuncs = siteFunctions(dynamoClient, config, log);
34
36
  const siteCandidateFuncs = siteCandidateFunctions(dynamoClient, config, log);
35
37
  const organizationFuncs = organizationFunctions(dynamoClient, config, log);
38
+ const configurationFuncs = configurationFunctions(dynamoClient, config);
36
39
 
37
40
  return {
38
41
  ...auditFuncs,
39
42
  ...siteFuncs,
40
43
  ...siteCandidateFuncs,
41
44
  ...organizationFuncs,
45
+ ...configurationFuncs,
42
46
  };
43
47
  };
@@ -50,6 +50,32 @@ export const getOrganizationByID = async (
50
50
  return isObject(dynamoItem) ? OrganizationDto.fromDynamoItem(dynamoItem) : null;
51
51
  };
52
52
 
53
+ /**
54
+ * Retrieves an organization by its IMS org ID.
55
+ *
56
+ * @param {DynamoDbClient} dynamoClient - The DynamoDB client.
57
+ * @param {DataAccessConfig} config - The data access config.
58
+ * @param {string} imsOrgId - Organization identifier on IMS, in the format of {id}@AdobeOrg
59
+ * @returns {Promise<Readonly<Organization>>} A promise that resolves to an organization, if found.
60
+ */
61
+ export const getOrganizationByImsOrgID = async (
62
+ dynamoClient,
63
+ config,
64
+ imsOrgId,
65
+ ) => {
66
+ const dynamoItems = await dynamoClient.query({
67
+ TableName: config.tableNameOrganizations,
68
+ IndexName: config.indexNameAllOrganizationsByImsOrgId,
69
+ KeyConditionExpression: 'imsOrgId = :imsOrgId',
70
+ ExpressionAttributeValues: {
71
+ ':imsOrgId': imsOrgId,
72
+ },
73
+ Limit: 1,
74
+ });
75
+
76
+ return dynamoItems.length > 0 ? OrganizationDto.fromDynamoItem(dynamoItems[0]) : null;
77
+ };
78
+
53
79
  /**
54
80
  * Adds an organization.
55
81
  *
@@ -15,6 +15,7 @@ import {
15
15
  addOrganization,
16
16
  updateOrganization,
17
17
  removeOrganization,
18
+ getOrganizationByImsOrgID,
18
19
  } from './accessPatterns.js';
19
20
 
20
21
  export const organizationFunctions = (dynamoClient, config, log) => ({
@@ -24,6 +25,11 @@ export const organizationFunctions = (dynamoClient, config, log) => ({
24
25
  config,
25
26
  organizationId,
26
27
  ),
28
+ getOrganizationByImsOrgID: (imsOrgId) => getOrganizationByImsOrgID(
29
+ dynamoClient,
30
+ config,
31
+ imsOrgId,
32
+ ),
27
33
  addOrganization: (organizationData) => addOrganization(
28
34
  dynamoClient,
29
35
  config,