@adobe/spacecat-shared-data-access 1.0.2 → 1.1.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 +7 -0
- package/package.json +2 -2
- package/src/dto/audit.js +2 -0
- package/src/dto/site.js +4 -0
- package/src/index.d.ts +22 -1
- package/src/index.js +28 -1
- package/src/models/audit.js +5 -0
- package/src/models/site.js +11 -0
- package/src/service/audits/accessPatterns.js +58 -29
- package/src/service/audits/index.js +7 -1
- package/src/service/index.js +4 -3
- package/src/service/sites/accessPatterns.js +55 -26
- package/src/service/sites/index.js +11 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [@adobe/spacecat-shared-data-access-v1.1.0](https://github.com/adobe-rnd/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v1.0.2...@adobe/spacecat-shared-data-access-v1.1.0) (2023-12-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* allow configuration from ctx / add missing fields ([#24](https://github.com/adobe-rnd/spacecat-shared/issues/24)) ([6959f89](https://github.com/adobe-rnd/spacecat-shared/commit/6959f895ed9b167f421b201f856ef871bd2a335c))
|
|
7
|
+
|
|
1
8
|
# [@adobe/spacecat-shared-data-access-v1.0.2](https://github.com/adobe-rnd/spacecat-shared/compare/@adobe/spacecat-shared-data-access-v1.0.1...@adobe/spacecat-shared-data-access-v1.0.2) (2023-12-02)
|
|
2
9
|
|
|
3
10
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/spacecat-shared-data-access",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Shared modules of the Spacecat Services - Data Access",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/service/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"access": "public"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@adobe/spacecat-shared-dynamo": "1.
|
|
32
|
+
"@adobe/spacecat-shared-dynamo": "1.2.3",
|
|
33
33
|
"@adobe/spacecat-shared-utils": "1.2.0",
|
|
34
34
|
"@aws-sdk/client-dynamodb": "3.465.0",
|
|
35
35
|
"@aws-sdk/lib-dynamodb": "3.465.0",
|
package/src/dto/audit.js
CHANGED
|
@@ -44,6 +44,7 @@ export const AuditDto = {
|
|
|
44
44
|
auditType: audit.getAuditType(),
|
|
45
45
|
expiresAt: convertDateToEpochSeconds(audit.getExpiresAt()),
|
|
46
46
|
fullAuditRef: audit.getFullAuditRef(),
|
|
47
|
+
isLive: audit.isLive(),
|
|
47
48
|
SK: `${audit.getAuditType()}#${audit.getAuditedAt()}`,
|
|
48
49
|
...latestAuditProps,
|
|
49
50
|
};
|
|
@@ -62,6 +63,7 @@ export const AuditDto = {
|
|
|
62
63
|
auditType: dynamoItem.auditType,
|
|
63
64
|
expiresAt: parseEpochToDate(dynamoItem.expiresAt),
|
|
64
65
|
fullAuditRef: dynamoItem.fullAuditRef,
|
|
66
|
+
isLive: dynamoItem.isLive,
|
|
65
67
|
};
|
|
66
68
|
|
|
67
69
|
return createAudit(auditData);
|
package/src/dto/site.js
CHANGED
|
@@ -24,7 +24,9 @@ export const SiteDto = {
|
|
|
24
24
|
toDynamoItem: (site) => ({
|
|
25
25
|
id: site.getId(),
|
|
26
26
|
baseURL: site.getBaseURL(),
|
|
27
|
+
gitHubURL: site.getGitHubURL(),
|
|
27
28
|
imsOrgId: site.getImsOrgId(),
|
|
29
|
+
isLive: site.isLive(),
|
|
28
30
|
createdAt: site.getCreatedAt(),
|
|
29
31
|
updatedAt: site.getUpdatedAt(),
|
|
30
32
|
GSI1PK: 'ALL_SITES',
|
|
@@ -39,7 +41,9 @@ export const SiteDto = {
|
|
|
39
41
|
const siteData = {
|
|
40
42
|
id: dynamoItem.id,
|
|
41
43
|
baseURL: dynamoItem.baseURL,
|
|
44
|
+
gitHubURL: dynamoItem.gitHubURL,
|
|
42
45
|
imsOrgId: dynamoItem.imsOrgId,
|
|
46
|
+
isLive: dynamoItem.isLive,
|
|
43
47
|
createdAt: dynamoItem.createdAt,
|
|
44
48
|
updatedAt: dynamoItem.updatedAt,
|
|
45
49
|
};
|
package/src/index.d.ts
CHANGED
|
@@ -19,18 +19,22 @@ export interface Audit {
|
|
|
19
19
|
getAuditType: () => object;
|
|
20
20
|
getExpiresAt: () => Date;
|
|
21
21
|
getFullAuditRef: () => string;
|
|
22
|
+
isLive: () => boolean;
|
|
22
23
|
getScores: () => object;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export interface Site {
|
|
26
27
|
getId: () => string;
|
|
27
28
|
getBaseURL: () => string;
|
|
29
|
+
getGitHubURL: () => string;
|
|
28
30
|
getImsOrgId: () => string;
|
|
29
31
|
getCreatedAt: () => string;
|
|
30
32
|
getUpdatedAt: () => string;
|
|
31
33
|
getAudits: () => Audit[];
|
|
32
|
-
|
|
34
|
+
isLive: () => boolean;
|
|
33
35
|
setAudits: (audits: Audit[]) => Site;
|
|
36
|
+
toggleLive: () => Site;
|
|
37
|
+
updateImsOrgId: (imsOrgId: string) => Site;
|
|
34
38
|
}
|
|
35
39
|
|
|
36
40
|
export interface DataAccess {
|
|
@@ -49,6 +53,12 @@ export interface DataAccess {
|
|
|
49
53
|
getLatestAuditsForSite: (
|
|
50
54
|
siteId: string,
|
|
51
55
|
) => Promise<Audit[]>;
|
|
56
|
+
addAudit: (
|
|
57
|
+
auditData: object,
|
|
58
|
+
) => Promise<Audit>;
|
|
59
|
+
removeAuditsForSite: (
|
|
60
|
+
siteId: string,
|
|
61
|
+
) => Promise<void>;
|
|
52
62
|
getSites: () => Promise<Site[]>;
|
|
53
63
|
getSitesToAudit: () => Promise<string[]>;
|
|
54
64
|
getSitesWithLatestAudit: (
|
|
@@ -82,6 +92,17 @@ export interface DataAccess {
|
|
|
82
92
|
) => Promise<void>;
|
|
83
93
|
}
|
|
84
94
|
|
|
95
|
+
interface DataAccessConfig {
|
|
96
|
+
tableNameAudits: string;
|
|
97
|
+
tableNameLatestAudits: string;
|
|
98
|
+
tableNameSites: string;
|
|
99
|
+
indexNameAllSites: string;
|
|
100
|
+
indexNameAllLatestAuditScores: string;
|
|
101
|
+
pkAllSites: string;
|
|
102
|
+
pkAllLatestAudits: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
85
105
|
export function createDataAccess(
|
|
106
|
+
config: DataAccessConfig,
|
|
86
107
|
logger: object,
|
|
87
108
|
): DataAccess;
|
package/src/index.js
CHANGED
|
@@ -12,11 +12,38 @@
|
|
|
12
12
|
|
|
13
13
|
import { createDataAccess } from './service/index.js';
|
|
14
14
|
|
|
15
|
+
const TABLE_NAME_AUDITS = 'spacecat-services-audits';
|
|
16
|
+
const TABLE_NAME_LATEST_AUDITS = 'spacecat-services-latest-audits';
|
|
17
|
+
const TABLE_NAME_SITES = 'spacecat-services-sites';
|
|
18
|
+
|
|
19
|
+
const INDEX_NAME_ALL_SITES = 'spacecat-services-all-sites';
|
|
20
|
+
const INDEX_NAME_ALL_LATEST_AUDIT_SCORES = 'spacecat-services-all-latest-audit-scores';
|
|
21
|
+
|
|
22
|
+
const PK_ALL_SITES = 'ALL_SITES';
|
|
23
|
+
const PK_ALL_LATEST_AUDITS = 'ALL_LATEST_AUDITS';
|
|
24
|
+
|
|
15
25
|
export default function dataAccessWrapper(fn) {
|
|
16
26
|
return async (request, context) => {
|
|
17
27
|
if (!context.dataAccess) {
|
|
18
28
|
const { log } = context;
|
|
19
|
-
|
|
29
|
+
|
|
30
|
+
const {
|
|
31
|
+
DYNAMO_TABLE_NAME_AUDITS = TABLE_NAME_AUDITS,
|
|
32
|
+
DYNAMO_TABLE_NAME_LATEST_AUDITS = TABLE_NAME_LATEST_AUDITS,
|
|
33
|
+
DYNAMO_TABLE_NAME_SITES = TABLE_NAME_SITES,
|
|
34
|
+
DYNAMO_INDEX_NAME_ALL_SITES = INDEX_NAME_ALL_SITES,
|
|
35
|
+
DYNAMO_INDEX_NAME_ALL_LATEST_AUDIT_SCORES = INDEX_NAME_ALL_LATEST_AUDIT_SCORES,
|
|
36
|
+
} = context.env;
|
|
37
|
+
|
|
38
|
+
context.dataAccess = createDataAccess({
|
|
39
|
+
tableNameAudits: DYNAMO_TABLE_NAME_AUDITS,
|
|
40
|
+
tableNameLatestAudits: DYNAMO_TABLE_NAME_LATEST_AUDITS,
|
|
41
|
+
tableNameSites: DYNAMO_TABLE_NAME_SITES,
|
|
42
|
+
indexNameAllSites: DYNAMO_INDEX_NAME_ALL_SITES,
|
|
43
|
+
indexNameAllLatestAuditScores: DYNAMO_INDEX_NAME_ALL_LATEST_AUDIT_SCORES,
|
|
44
|
+
pkAllSites: PK_ALL_SITES,
|
|
45
|
+
pkAllLatestAudits: PK_ALL_LATEST_AUDITS,
|
|
46
|
+
}, log);
|
|
20
47
|
}
|
|
21
48
|
|
|
22
49
|
return fn(request, context);
|
package/src/models/audit.js
CHANGED
|
@@ -58,6 +58,7 @@ const Audit = (data = {}) => {
|
|
|
58
58
|
self.getAuditType = () => self.state.auditType.toLowerCase();
|
|
59
59
|
self.getExpiresAt = () => self.state.expiresAt;
|
|
60
60
|
self.getFullAuditRef = () => self.state.fullAuditRef;
|
|
61
|
+
self.isLive = () => self.state.isLive;
|
|
61
62
|
self.getScores = () => self.getAuditResult();
|
|
62
63
|
|
|
63
64
|
return Object.freeze(self);
|
|
@@ -99,5 +100,9 @@ export const createAudit = (data) => {
|
|
|
99
100
|
newState.expiresAt.setDate(newState.expiresAt.getDate() + EXPIRES_IN_DAYS);
|
|
100
101
|
}
|
|
101
102
|
|
|
103
|
+
if (!Object.prototype.hasOwnProperty.call(newState, 'isLive')) {
|
|
104
|
+
newState.isLive = false;
|
|
105
|
+
}
|
|
106
|
+
|
|
102
107
|
return Audit(newState);
|
|
103
108
|
};
|
package/src/models/site.js
CHANGED
|
@@ -24,7 +24,9 @@ const Site = (data = {}) => {
|
|
|
24
24
|
|
|
25
25
|
self.getAudits = () => self.state.audits;
|
|
26
26
|
self.getBaseURL = () => self.state.baseURL;
|
|
27
|
+
self.getGitHubURL = () => self.state.gitHubURL;
|
|
27
28
|
self.getImsOrgId = () => self.state.imsOrgId;
|
|
29
|
+
self.isLive = () => self.state.isLive;
|
|
28
30
|
|
|
29
31
|
// TODO: updating the baseURL is not supported yet, it will require a transact write
|
|
30
32
|
// on dynamodb (put then delete) since baseURL is part of the primary key, something like:
|
|
@@ -79,6 +81,11 @@ const Site = (data = {}) => {
|
|
|
79
81
|
return self;
|
|
80
82
|
};
|
|
81
83
|
|
|
84
|
+
self.toggleLive = () => {
|
|
85
|
+
self.state.isLive = !self.state.isLive;
|
|
86
|
+
return self;
|
|
87
|
+
};
|
|
88
|
+
|
|
82
89
|
return Object.freeze(self);
|
|
83
90
|
};
|
|
84
91
|
|
|
@@ -95,6 +102,10 @@ export const createSite = (data) => {
|
|
|
95
102
|
throw new Error('Base URL must be a valid URL');
|
|
96
103
|
}
|
|
97
104
|
|
|
105
|
+
if (!Object.prototype.hasOwnProperty.call(newState, 'isLive')) {
|
|
106
|
+
newState.isLive = false;
|
|
107
|
+
}
|
|
108
|
+
|
|
98
109
|
if (!Array.isArray(newState.audits)) {
|
|
99
110
|
newState.audits = [];
|
|
100
111
|
}
|
|
@@ -15,25 +15,21 @@ import { isObject } from '@adobe/spacecat-shared-utils';
|
|
|
15
15
|
import { AuditDto } from '../../dto/audit.js';
|
|
16
16
|
import { createAudit } from '../../models/audit.js';
|
|
17
17
|
|
|
18
|
-
const TABLE_NAME_AUDITS = 'audits';
|
|
19
|
-
const TABLE_NAME_LATEST_AUDITS = 'latest_audits';
|
|
20
|
-
const INDEX_NAME_ALL_LATEST_AUDIT_SCORES = 'all_latest_audit_scores';
|
|
21
|
-
const PK_ALL_LATEST_AUDITS = 'ALL_LATEST_AUDITS';
|
|
22
|
-
|
|
23
18
|
/**
|
|
24
19
|
* Retrieves audits for a specified site. If an audit type is provided,
|
|
25
20
|
* it returns only audits of that type.
|
|
26
21
|
*
|
|
27
22
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
23
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
28
24
|
* @param {Logger} log - The logger.
|
|
29
25
|
* @param {string} siteId - The ID of the site for which audits are being retrieved.
|
|
30
26
|
* @param {string} [auditType] - Optional. The type of audits to retrieve.
|
|
31
27
|
* @returns {Promise<Readonly<Audit>[]>} A promise that resolves to an array of audits
|
|
32
28
|
* for the specified site.
|
|
33
29
|
*/
|
|
34
|
-
export const getAuditsForSite = async (dynamoClient, log, siteId, auditType) => {
|
|
30
|
+
export const getAuditsForSite = async (dynamoClient, config, log, siteId, auditType) => {
|
|
35
31
|
const queryParams = {
|
|
36
|
-
TableName:
|
|
32
|
+
TableName: config.tableNameAudits,
|
|
37
33
|
KeyConditionExpression: 'siteId = :siteId',
|
|
38
34
|
ExpressionAttributeValues: {
|
|
39
35
|
':siteId': siteId,
|
|
@@ -54,6 +50,7 @@ export const getAuditsForSite = async (dynamoClient, log, siteId, auditType) =>
|
|
|
54
50
|
* Retrieves a specific audit for a specified site.
|
|
55
51
|
*
|
|
56
52
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
53
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
57
54
|
* @param {Logger} log - The logger.
|
|
58
55
|
* @param {string} siteId - The ID of the site for which to retrieve the audit.
|
|
59
56
|
* @param {string} auditType - The type of audit to retrieve.
|
|
@@ -62,13 +59,14 @@ export const getAuditsForSite = async (dynamoClient, log, siteId, auditType) =>
|
|
|
62
59
|
*/
|
|
63
60
|
export const getAuditForSite = async (
|
|
64
61
|
dynamoClient,
|
|
62
|
+
config,
|
|
65
63
|
log,
|
|
66
64
|
siteId,
|
|
67
65
|
auditType,
|
|
68
66
|
auditedAt,
|
|
69
67
|
) => {
|
|
70
68
|
const audit = await dynamoClient.query({
|
|
71
|
-
TableName:
|
|
69
|
+
TableName: config.tableNameAudits,
|
|
72
70
|
KeyConditionExpression: 'siteId = :siteId AND SK = :sk',
|
|
73
71
|
ExpressionAttributeValues: {
|
|
74
72
|
':siteId': siteId,
|
|
@@ -84,6 +82,7 @@ export const getAuditForSite = async (
|
|
|
84
82
|
* Retrieves the latest audits of a specific type across all sites.
|
|
85
83
|
*
|
|
86
84
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
85
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
87
86
|
* @param {Logger} log - The logger.
|
|
88
87
|
* @param {string} auditType - The type of audits to retrieve.
|
|
89
88
|
* @param {boolean} ascending - Determines if the audits should be sorted ascending
|
|
@@ -93,16 +92,17 @@ export const getAuditForSite = async (
|
|
|
93
92
|
*/
|
|
94
93
|
export const getLatestAudits = async (
|
|
95
94
|
dynamoClient,
|
|
95
|
+
config,
|
|
96
96
|
log,
|
|
97
97
|
auditType,
|
|
98
98
|
ascending = true,
|
|
99
99
|
) => {
|
|
100
100
|
const dynamoItems = await dynamoClient.query({
|
|
101
|
-
TableName:
|
|
102
|
-
IndexName:
|
|
101
|
+
TableName: config.tableNameLatestAudits,
|
|
102
|
+
IndexName: config.indexNameAllLatestAuditScores,
|
|
103
103
|
KeyConditionExpression: 'GSI1PK = :gsi1pk AND begins_with(GSI1SK, :auditType)',
|
|
104
104
|
ExpressionAttributeValues: {
|
|
105
|
-
':gsi1pk':
|
|
105
|
+
':gsi1pk': config.pkAllLatestAudits,
|
|
106
106
|
':auditType': `${auditType}#`,
|
|
107
107
|
},
|
|
108
108
|
ScanIndexForward: ascending, // Sorts ascending if true, descending if false
|
|
@@ -115,14 +115,20 @@ export const getLatestAudits = async (
|
|
|
115
115
|
* Retrieves latest audits for a specified site.
|
|
116
116
|
*
|
|
117
117
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
118
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
118
119
|
* @param {Logger} log - The logger.
|
|
119
120
|
* @param {string} siteId - The ID of the site for which audits are being retrieved.
|
|
120
121
|
* @returns {Promise<Readonly<Audit>[]>} A promise that resolves to an array of latest audits
|
|
121
122
|
* for the specified site.
|
|
122
123
|
*/
|
|
123
|
-
export const getLatestAuditsForSite = async (
|
|
124
|
+
export const getLatestAuditsForSite = async (
|
|
125
|
+
dynamoClient,
|
|
126
|
+
config,
|
|
127
|
+
log,
|
|
128
|
+
siteId,
|
|
129
|
+
) => {
|
|
124
130
|
const queryParams = {
|
|
125
|
-
TableName:
|
|
131
|
+
TableName: config.tableNameLatestAudits,
|
|
126
132
|
KeyConditionExpression: 'siteId = :siteId',
|
|
127
133
|
ExpressionAttributeValues: { ':siteId': siteId },
|
|
128
134
|
};
|
|
@@ -136,6 +142,7 @@ export const getLatestAuditsForSite = async (dynamoClient, log, siteId) => {
|
|
|
136
142
|
* Retrieves the latest audit for a specified site and audit type.
|
|
137
143
|
*
|
|
138
144
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
145
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
139
146
|
* @param {Logger} log - The logger.
|
|
140
147
|
* @param {string} siteId - The ID of the site for which the latest audit is being retrieved.
|
|
141
148
|
* @param {string} auditType - The type of audit to retrieve the latest instance of.
|
|
@@ -144,12 +151,13 @@ export const getLatestAuditsForSite = async (dynamoClient, log, siteId) => {
|
|
|
144
151
|
*/
|
|
145
152
|
export const getLatestAuditForSite = async (
|
|
146
153
|
dynamoClient,
|
|
154
|
+
config,
|
|
147
155
|
log,
|
|
148
156
|
siteId,
|
|
149
157
|
auditType,
|
|
150
158
|
) => {
|
|
151
159
|
const latestAudit = await dynamoClient.query({
|
|
152
|
-
TableName:
|
|
160
|
+
TableName: config.tableNameLatestAudits,
|
|
153
161
|
KeyConditionExpression: 'siteId = :siteId AND begins_with(SK, :auditType)',
|
|
154
162
|
ExpressionAttributeValues: {
|
|
155
163
|
':siteId': siteId,
|
|
@@ -165,14 +173,21 @@ export const getLatestAuditForSite = async (
|
|
|
165
173
|
* Adds an audit.
|
|
166
174
|
*
|
|
167
175
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
176
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
168
177
|
* @param {Logger} log - The logger.
|
|
169
178
|
* @param {object} auditData - The audit data.
|
|
170
179
|
* @returns {Promise<Readonly<Audit>>}
|
|
171
180
|
*/
|
|
172
|
-
export const addAudit = async (
|
|
181
|
+
export const addAudit = async (
|
|
182
|
+
dynamoClient,
|
|
183
|
+
config,
|
|
184
|
+
log,
|
|
185
|
+
auditData,
|
|
186
|
+
) => {
|
|
173
187
|
const audit = createAudit(auditData);
|
|
174
188
|
const existingAudit = await getAuditForSite(
|
|
175
189
|
dynamoClient,
|
|
190
|
+
config,
|
|
176
191
|
log,
|
|
177
192
|
audit.getSiteId(),
|
|
178
193
|
audit.getAuditType(),
|
|
@@ -184,8 +199,8 @@ export const addAudit = async (dynamoClient, log, auditData) => {
|
|
|
184
199
|
}
|
|
185
200
|
|
|
186
201
|
// TODO: Add transaction support
|
|
187
|
-
await dynamoClient.putItem(
|
|
188
|
-
await dynamoClient.putItem(
|
|
202
|
+
await dynamoClient.putItem(config.tableNameAudits, AuditDto.toDynamoItem(audit));
|
|
203
|
+
await dynamoClient.putItem(config.tableNameLatestAudits, AuditDto.toDynamoItem(audit, true));
|
|
189
204
|
|
|
190
205
|
return audit;
|
|
191
206
|
};
|
|
@@ -193,18 +208,26 @@ export const addAudit = async (dynamoClient, log, auditData) => {
|
|
|
193
208
|
/**
|
|
194
209
|
* Removes audits from the database.
|
|
195
210
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
196
|
-
* @param {
|
|
211
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
197
212
|
* @param audits
|
|
198
213
|
* @param latest
|
|
199
214
|
* @returns {Promise<void>}
|
|
200
215
|
*/
|
|
201
|
-
async function removeAudits(
|
|
202
|
-
|
|
216
|
+
async function removeAudits(
|
|
217
|
+
dynamoClient,
|
|
218
|
+
config,
|
|
219
|
+
audits,
|
|
220
|
+
latest = false,
|
|
221
|
+
) {
|
|
222
|
+
const tableName = latest ? config.tableNameLatestAudits : config.tableNameAudits;
|
|
203
223
|
// TODO: use batch-remove (needs dynamo client update)
|
|
204
|
-
const removeAuditPromises = audits.map((audit) => dynamoClient.removeItem(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
224
|
+
const removeAuditPromises = audits.map((audit) => dynamoClient.removeItem(
|
|
225
|
+
tableName,
|
|
226
|
+
{
|
|
227
|
+
siteId: audit.getSiteId(),
|
|
228
|
+
SK: `${audit.getAuditType()}#${audit.getAuditedAt()}`,
|
|
229
|
+
},
|
|
230
|
+
));
|
|
208
231
|
|
|
209
232
|
await Promise.all(removeAuditPromises);
|
|
210
233
|
}
|
|
@@ -213,17 +236,23 @@ async function removeAudits(dynamoClient, audits, latest = false) {
|
|
|
213
236
|
* Removes all audits for a specified site and the latest audit entry.
|
|
214
237
|
*
|
|
215
238
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
239
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
216
240
|
* @param {Logger} log - The logger.
|
|
217
241
|
* @param {string} siteId - The ID of the site for which audits are being removed.
|
|
218
242
|
* @returns {Promise<void>}
|
|
219
243
|
*/
|
|
220
|
-
export const removeAuditsForSite = async (
|
|
244
|
+
export const removeAuditsForSite = async (
|
|
245
|
+
dynamoClient,
|
|
246
|
+
config,
|
|
247
|
+
log,
|
|
248
|
+
siteId,
|
|
249
|
+
) => {
|
|
221
250
|
try {
|
|
222
|
-
const audits = await getAuditsForSite(dynamoClient, log, siteId);
|
|
223
|
-
const latestAudits = await getLatestAuditsForSite(dynamoClient, log, siteId);
|
|
251
|
+
const audits = await getAuditsForSite(dynamoClient, config, log, siteId);
|
|
252
|
+
const latestAudits = await getLatestAuditsForSite(dynamoClient, config, log, siteId);
|
|
224
253
|
|
|
225
|
-
await removeAudits(dynamoClient, audits);
|
|
226
|
-
await removeAudits(dynamoClient, latestAudits, true);
|
|
254
|
+
await removeAudits(dynamoClient, config, audits);
|
|
255
|
+
await removeAudits(dynamoClient, config, latestAudits, true);
|
|
227
256
|
} catch (error) {
|
|
228
257
|
log.error(`Error removing audits for site ${siteId}: ${error.message}`);
|
|
229
258
|
throw error;
|
|
@@ -18,9 +18,10 @@ import {
|
|
|
18
18
|
removeAuditsForSite,
|
|
19
19
|
} from './accessPatterns.js';
|
|
20
20
|
|
|
21
|
-
export const auditFunctions = (dynamoClient, log) => ({
|
|
21
|
+
export const auditFunctions = (dynamoClient, config, log) => ({
|
|
22
22
|
getAuditForSite: (siteId, auditType, auditedAt) => getAuditForSite(
|
|
23
23
|
dynamoClient,
|
|
24
|
+
config,
|
|
24
25
|
log,
|
|
25
26
|
siteId,
|
|
26
27
|
auditType,
|
|
@@ -28,29 +29,34 @@ export const auditFunctions = (dynamoClient, log) => ({
|
|
|
28
29
|
),
|
|
29
30
|
getAuditsForSite: (siteId, auditType) => getAuditsForSite(
|
|
30
31
|
dynamoClient,
|
|
32
|
+
config,
|
|
31
33
|
log,
|
|
32
34
|
siteId,
|
|
33
35
|
auditType,
|
|
34
36
|
),
|
|
35
37
|
getLatestAudits: (auditType, ascending) => getLatestAudits(
|
|
36
38
|
dynamoClient,
|
|
39
|
+
config,
|
|
37
40
|
log,
|
|
38
41
|
auditType,
|
|
39
42
|
ascending,
|
|
40
43
|
),
|
|
41
44
|
getLatestAuditForSite: (siteId, auditType) => getLatestAuditForSite(
|
|
42
45
|
dynamoClient,
|
|
46
|
+
config,
|
|
43
47
|
log,
|
|
44
48
|
siteId,
|
|
45
49
|
auditType,
|
|
46
50
|
),
|
|
47
51
|
addAudit: (auditData) => addAudit(
|
|
48
52
|
dynamoClient,
|
|
53
|
+
config,
|
|
49
54
|
log,
|
|
50
55
|
auditData,
|
|
51
56
|
),
|
|
52
57
|
removeAuditsForSite: (siteId) => removeAuditsForSite(
|
|
53
58
|
dynamoClient,
|
|
59
|
+
config,
|
|
54
60
|
log,
|
|
55
61
|
siteId,
|
|
56
62
|
),
|
package/src/service/index.js
CHANGED
|
@@ -17,14 +17,15 @@ import { siteFunctions } from './sites/index.js';
|
|
|
17
17
|
/**
|
|
18
18
|
* Creates a data access object.
|
|
19
19
|
*
|
|
20
|
+
* @param {DataAccessConfig} config configuration
|
|
20
21
|
* @param {Logger} log logger
|
|
21
22
|
* @returns {object} data access object
|
|
22
23
|
*/
|
|
23
|
-
export const createDataAccess = (log = console) => {
|
|
24
|
+
export const createDataAccess = (config, log = console) => {
|
|
24
25
|
const dynamoClient = createClient(log);
|
|
25
26
|
|
|
26
|
-
const auditFuncs = auditFunctions(dynamoClient, log);
|
|
27
|
-
const siteFuncs = siteFunctions(dynamoClient, log);
|
|
27
|
+
const auditFuncs = auditFunctions(dynamoClient, config, log);
|
|
28
|
+
const siteFuncs = siteFunctions(dynamoClient, config, log);
|
|
28
29
|
|
|
29
30
|
return {
|
|
30
31
|
...auditFuncs,
|
|
@@ -21,23 +21,20 @@ import {
|
|
|
21
21
|
import { createSite } from '../../models/site.js';
|
|
22
22
|
import { SiteDto } from '../../dto/site.js';
|
|
23
23
|
|
|
24
|
-
const INDEX_NAME_ALL_SITES = 'all_sites';
|
|
25
|
-
const PK_ALL_SITES = 'ALL_SITES';
|
|
26
|
-
const TABLE_NAME_SITES = 'sites';
|
|
27
|
-
|
|
28
24
|
/**
|
|
29
25
|
* Retrieves all sites.
|
|
30
26
|
*
|
|
31
27
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
28
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
32
29
|
* @returns {Promise<Readonly<Site>[]>} A promise that resolves to an array of all sites.
|
|
33
30
|
*/
|
|
34
|
-
export const getSites = async (dynamoClient) => {
|
|
31
|
+
export const getSites = async (dynamoClient, config) => {
|
|
35
32
|
const dynamoItems = await dynamoClient.query({
|
|
36
|
-
TableName:
|
|
37
|
-
IndexName:
|
|
33
|
+
TableName: config.tableNameSites,
|
|
34
|
+
IndexName: config.indexNameAllSites,
|
|
38
35
|
KeyConditionExpression: 'GSI1PK = :gsi1pk',
|
|
39
36
|
ExpressionAttributeValues: {
|
|
40
|
-
':gsi1pk':
|
|
37
|
+
':gsi1pk': config.pkAllSites,
|
|
41
38
|
},
|
|
42
39
|
});
|
|
43
40
|
|
|
@@ -48,10 +45,11 @@ export const getSites = async (dynamoClient) => {
|
|
|
48
45
|
* Retrieves a list of base URLs for all sites.
|
|
49
46
|
*
|
|
50
47
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
48
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
51
49
|
* @returns {Promise<Array<string>>} A promise that resolves to an array of base URLs for all sites.
|
|
52
50
|
*/
|
|
53
|
-
export const getSitesToAudit = async (dynamoClient) => {
|
|
54
|
-
const sites = await getSites(dynamoClient);
|
|
51
|
+
export const getSitesToAudit = async (dynamoClient, config) => {
|
|
52
|
+
const sites = await getSites(dynamoClient, config);
|
|
55
53
|
|
|
56
54
|
return sites.map((site) => site.getBaseURL());
|
|
57
55
|
};
|
|
@@ -60,6 +58,7 @@ export const getSitesToAudit = async (dynamoClient) => {
|
|
|
60
58
|
* Retrieves sites with their latest audit of a specified type.
|
|
61
59
|
*
|
|
62
60
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
61
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
63
62
|
* @param {Logger} log - The logger.
|
|
64
63
|
* @param {string} auditType - The type of the latest audits to retrieve for each site.
|
|
65
64
|
* @param {boolean} [sortAuditsAscending] - Optional. Determines if the audits
|
|
@@ -69,13 +68,14 @@ export const getSitesToAudit = async (dynamoClient) => {
|
|
|
69
68
|
*/
|
|
70
69
|
export const getSitesWithLatestAudit = async (
|
|
71
70
|
dynamoClient,
|
|
71
|
+
config,
|
|
72
72
|
log,
|
|
73
73
|
auditType,
|
|
74
74
|
sortAuditsAscending = true,
|
|
75
75
|
) => {
|
|
76
76
|
const [sites, latestAudits] = await Promise.all([
|
|
77
|
-
getSites(dynamoClient),
|
|
78
|
-
getLatestAudits(dynamoClient, log, auditType, sortAuditsAscending),
|
|
77
|
+
getSites(dynamoClient, config),
|
|
78
|
+
getLatestAudits(dynamoClient, config, log, auditType, sortAuditsAscending),
|
|
79
79
|
]);
|
|
80
80
|
|
|
81
81
|
const sitesMap = new Map(sites.map((site) => [site.getId(), site]));
|
|
@@ -94,6 +94,7 @@ export const getSitesWithLatestAudit = async (
|
|
|
94
94
|
* Retrieves a site by its base URL.
|
|
95
95
|
*
|
|
96
96
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
97
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
97
98
|
* @param {Logger} log - The logger.
|
|
98
99
|
* @param {string} baseURL - The base URL of the site to retrieve.
|
|
99
100
|
* @returns {Promise<Readonly<Site>|null>} A promise that resolves to the site object if found,
|
|
@@ -101,15 +102,16 @@ export const getSitesWithLatestAudit = async (
|
|
|
101
102
|
*/
|
|
102
103
|
export const getSiteByBaseURL = async (
|
|
103
104
|
dynamoClient,
|
|
105
|
+
config,
|
|
104
106
|
log,
|
|
105
107
|
baseURL,
|
|
106
108
|
) => {
|
|
107
109
|
const dynamoItems = await dynamoClient.query({
|
|
108
|
-
TableName:
|
|
109
|
-
IndexName:
|
|
110
|
+
TableName: config.tableNameSites,
|
|
111
|
+
IndexName: config.indexNameAllSites,
|
|
110
112
|
KeyConditionExpression: 'GSI1PK = :gsi1pk AND baseURL = :baseURL',
|
|
111
113
|
ExpressionAttributeValues: {
|
|
112
|
-
':gsi1pk':
|
|
114
|
+
':gsi1pk': config.pkAllSites,
|
|
113
115
|
':baseURL': baseURL,
|
|
114
116
|
},
|
|
115
117
|
Limit: 1,
|
|
@@ -126,6 +128,7 @@ export const getSiteByBaseURL = async (
|
|
|
126
128
|
* Retrieves a site by its base URL, along with associated audit information.
|
|
127
129
|
*
|
|
128
130
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
131
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
129
132
|
* @param {Logger} log - The logger.
|
|
130
133
|
* @param {string} baseUrl - The base URL of the site to retrieve.
|
|
131
134
|
* @param {string} auditType - The type of audits to retrieve for the site.
|
|
@@ -135,12 +138,13 @@ export const getSiteByBaseURL = async (
|
|
|
135
138
|
*/
|
|
136
139
|
export const getSiteByBaseURLWithAuditInfo = async (
|
|
137
140
|
dynamoClient,
|
|
141
|
+
config,
|
|
138
142
|
log,
|
|
139
143
|
baseUrl,
|
|
140
144
|
auditType,
|
|
141
145
|
latestOnly = false,
|
|
142
146
|
) => {
|
|
143
|
-
const site = await getSiteByBaseURL(dynamoClient, log, baseUrl);
|
|
147
|
+
const site = await getSiteByBaseURL(dynamoClient, config, log, baseUrl);
|
|
144
148
|
|
|
145
149
|
if (!isObject(site)) {
|
|
146
150
|
return null;
|
|
@@ -149,12 +153,14 @@ export const getSiteByBaseURLWithAuditInfo = async (
|
|
|
149
153
|
const audits = latestOnly
|
|
150
154
|
? [await getLatestAuditForSite(
|
|
151
155
|
dynamoClient,
|
|
156
|
+
config,
|
|
152
157
|
log,
|
|
153
158
|
site.getId(),
|
|
154
159
|
auditType,
|
|
155
160
|
)].filter((audit) => audit != null)
|
|
156
161
|
: await getAuditsForSite(
|
|
157
162
|
dynamoClient,
|
|
163
|
+
config,
|
|
158
164
|
log,
|
|
159
165
|
site.getId(),
|
|
160
166
|
auditType,
|
|
@@ -169,6 +175,7 @@ export const getSiteByBaseURLWithAuditInfo = async (
|
|
|
169
175
|
* Retrieves a site by its base URL, including all its audits.
|
|
170
176
|
*
|
|
171
177
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
178
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
172
179
|
* @param {Logger} log - The logger.
|
|
173
180
|
* @param {string} baseUrl - The base URL of the site to retrieve.
|
|
174
181
|
* @param {string} auditType - The type of audits to retrieve for the site.
|
|
@@ -177,15 +184,17 @@ export const getSiteByBaseURLWithAuditInfo = async (
|
|
|
177
184
|
*/
|
|
178
185
|
export const getSiteByBaseURLWithAudits = async (
|
|
179
186
|
dynamoClient,
|
|
187
|
+
config,
|
|
180
188
|
log,
|
|
181
189
|
baseUrl,
|
|
182
190
|
auditType,
|
|
183
|
-
) => getSiteByBaseURLWithAuditInfo(dynamoClient, log, baseUrl, auditType, false);
|
|
191
|
+
) => getSiteByBaseURLWithAuditInfo(dynamoClient, config, log, baseUrl, auditType, false);
|
|
184
192
|
|
|
185
193
|
/**
|
|
186
194
|
* Retrieves a site by its base URL, including only its latest audit.
|
|
187
195
|
*
|
|
188
196
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
197
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
189
198
|
* @param {Logger} log - The logger.
|
|
190
199
|
* @param {string} baseUrl - The base URL of the site to retrieve.
|
|
191
200
|
* @param {string} auditType - The type of the latest audit to retrieve for the site.
|
|
@@ -194,23 +203,31 @@ export const getSiteByBaseURLWithAudits = async (
|
|
|
194
203
|
*/
|
|
195
204
|
export const getSiteByBaseURLWithLatestAudit = async (
|
|
196
205
|
dynamoClient,
|
|
206
|
+
config,
|
|
197
207
|
log,
|
|
198
208
|
baseUrl,
|
|
199
209
|
auditType,
|
|
200
|
-
) => getSiteByBaseURLWithAuditInfo(dynamoClient, log, baseUrl, auditType, true);
|
|
210
|
+
) => getSiteByBaseURLWithAuditInfo(dynamoClient, config, log, baseUrl, auditType, true);
|
|
201
211
|
|
|
202
212
|
/**
|
|
203
213
|
* Adds a site.
|
|
204
214
|
*
|
|
205
215
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
216
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
206
217
|
* @param {Logger} log - The logger.
|
|
207
218
|
* @param {object} siteData - The site data.
|
|
208
219
|
* @returns {Promise<Readonly<Site>>}
|
|
209
220
|
*/
|
|
210
|
-
export const addSite = async (
|
|
221
|
+
export const addSite = async (
|
|
222
|
+
dynamoClient,
|
|
223
|
+
config,
|
|
224
|
+
log,
|
|
225
|
+
siteData,
|
|
226
|
+
) => {
|
|
211
227
|
const site = createSite(siteData);
|
|
212
228
|
const existingSite = await getSiteByBaseURL(
|
|
213
229
|
dynamoClient,
|
|
230
|
+
config,
|
|
214
231
|
log,
|
|
215
232
|
site.getBaseURL(),
|
|
216
233
|
);
|
|
@@ -219,7 +236,7 @@ export const addSite = async (dynamoClient, log, siteData) => {
|
|
|
219
236
|
throw new Error('Site already exists');
|
|
220
237
|
}
|
|
221
238
|
|
|
222
|
-
await dynamoClient.putItem(
|
|
239
|
+
await dynamoClient.putItem(config.tableNameSites, SiteDto.toDynamoItem(site));
|
|
223
240
|
|
|
224
241
|
return site;
|
|
225
242
|
};
|
|
@@ -228,18 +245,24 @@ export const addSite = async (dynamoClient, log, siteData) => {
|
|
|
228
245
|
* Updates a site.
|
|
229
246
|
*
|
|
230
247
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
248
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
231
249
|
* @param {Logger} log - The logger.
|
|
232
250
|
* @param {Site} site - The site.
|
|
233
251
|
* @returns {Promise<Readonly<Site>>} - The updated site.
|
|
234
252
|
*/
|
|
235
|
-
export const updateSite = async (
|
|
236
|
-
|
|
253
|
+
export const updateSite = async (
|
|
254
|
+
dynamoClient,
|
|
255
|
+
config,
|
|
256
|
+
log,
|
|
257
|
+
site,
|
|
258
|
+
) => {
|
|
259
|
+
const existingSite = await getSiteByBaseURL(dynamoClient, config, log, site.getBaseURL());
|
|
237
260
|
|
|
238
261
|
if (!isObject(existingSite)) {
|
|
239
262
|
throw new Error('Site not found');
|
|
240
263
|
}
|
|
241
264
|
|
|
242
|
-
await dynamoClient.putItem(
|
|
265
|
+
await dynamoClient.putItem(config.tableNameSites, SiteDto.toDynamoItem(site));
|
|
243
266
|
|
|
244
267
|
return site;
|
|
245
268
|
};
|
|
@@ -248,16 +271,22 @@ export const updateSite = async (dynamoClient, log, site) => {
|
|
|
248
271
|
* Removes a site and its related audits.
|
|
249
272
|
*
|
|
250
273
|
* @param {DynamoDbClient} dynamoClient - The DynamoDB client.
|
|
274
|
+
* @param {DataAccessConfig} config - The data access config.
|
|
251
275
|
* @param {Logger} log - The logger.
|
|
252
276
|
* @param {string} siteId - The ID of the site to remove.
|
|
253
277
|
* @returns {Promise<void>}
|
|
254
278
|
*/
|
|
255
|
-
export const removeSite = async (
|
|
279
|
+
export const removeSite = async (
|
|
280
|
+
dynamoClient,
|
|
281
|
+
config,
|
|
282
|
+
log,
|
|
283
|
+
siteId,
|
|
284
|
+
) => {
|
|
256
285
|
try {
|
|
257
286
|
// TODO: Add transaction support
|
|
258
|
-
await removeAuditsForSite(dynamoClient, log, siteId);
|
|
287
|
+
await removeAuditsForSite(dynamoClient, config, log, siteId);
|
|
259
288
|
|
|
260
|
-
await dynamoClient.removeItem(
|
|
289
|
+
await dynamoClient.removeItem(config.tableNameSites, { id: siteId });
|
|
261
290
|
} catch (error) {
|
|
262
291
|
log.error(`Error removing site: ${error.message}`);
|
|
263
292
|
throw error;
|
|
@@ -22,26 +22,31 @@ import {
|
|
|
22
22
|
updateSite,
|
|
23
23
|
} from './accessPatterns.js';
|
|
24
24
|
|
|
25
|
-
export const siteFunctions = (dynamoClient, log) => ({
|
|
25
|
+
export const siteFunctions = (dynamoClient, config, log) => ({
|
|
26
26
|
getSites: () => getSites(
|
|
27
27
|
dynamoClient,
|
|
28
|
+
config,
|
|
28
29
|
),
|
|
29
30
|
getSitesToAudit: () => getSitesToAudit(
|
|
30
31
|
dynamoClient,
|
|
32
|
+
config,
|
|
31
33
|
),
|
|
32
34
|
getSitesWithLatestAudit: (auditType, sortAuditsAscending) => getSitesWithLatestAudit(
|
|
33
35
|
dynamoClient,
|
|
36
|
+
config,
|
|
34
37
|
log,
|
|
35
38
|
auditType,
|
|
36
39
|
sortAuditsAscending,
|
|
37
40
|
),
|
|
38
41
|
getSiteByBaseURL: (baseUrl) => getSiteByBaseURL(
|
|
39
42
|
dynamoClient,
|
|
43
|
+
config,
|
|
40
44
|
log,
|
|
41
45
|
baseUrl,
|
|
42
46
|
),
|
|
43
47
|
getSiteByBaseURLWithAuditInfo: (baseUrl, auditType, latestOnly) => getSiteByBaseURLWithAuditInfo(
|
|
44
48
|
dynamoClient,
|
|
49
|
+
config,
|
|
45
50
|
log,
|
|
46
51
|
baseUrl,
|
|
47
52
|
auditType,
|
|
@@ -49,17 +54,19 @@ export const siteFunctions = (dynamoClient, log) => ({
|
|
|
49
54
|
),
|
|
50
55
|
getSiteByBaseURLWithAudits: (baseUrl, auditType) => getSiteByBaseURLWithAudits(
|
|
51
56
|
dynamoClient,
|
|
57
|
+
config,
|
|
52
58
|
log,
|
|
53
59
|
baseUrl,
|
|
54
60
|
auditType,
|
|
55
61
|
),
|
|
56
62
|
getSiteByBaseURLWithLatestAudit: (baseUrl, auditType) => getSiteByBaseURLWithLatestAudit(
|
|
57
63
|
dynamoClient,
|
|
64
|
+
config,
|
|
58
65
|
log,
|
|
59
66
|
baseUrl,
|
|
60
67
|
auditType,
|
|
61
68
|
),
|
|
62
|
-
addSite: (siteData) => addSite(dynamoClient, log, siteData),
|
|
63
|
-
updateSite: (site) => updateSite(dynamoClient, log, site),
|
|
64
|
-
removeSite: (siteId) => removeSite(dynamoClient, log, siteId),
|
|
69
|
+
addSite: (siteData) => addSite(dynamoClient, config, log, siteData),
|
|
70
|
+
updateSite: (site) => updateSite(dynamoClient, config, log, site),
|
|
71
|
+
removeSite: (siteId) => removeSite(dynamoClient, config, log, siteId),
|
|
65
72
|
});
|