Skip to content

Commit 54ff157

Browse files
author
Anmol Binani
committed
minor changes
2 parents 83f4035 + bbad0f9 commit 54ff157

12 files changed

+1120
-250
lines changed

.prettierrc

Lines changed: 0 additions & 5 deletions
This file was deleted.

.prettierrc.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"tabWidth": 2,
3+
"useTabs": false,
4+
"printWidth": 200,
5+
"trailingComma" : "none"
6+
}

lib/content-deployment.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@ async function deployNotificationTypes() {
1616
}
1717

1818
deployNotificationTypes();
19+
20+
module.exports = {
21+
deployNotificationTypes
22+
}

lib/notificationTypes.js

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,26 @@ const cds = require("@sap/cds");
77
const LOG = cds.log('notifications');
88

99
const defaultTemplate = {
10-
"NotificationTypeKey": "Default",
11-
"NotificationTypeVersion": "1",
12-
"Templates": [
10+
NotificationTypeKey: "Default",
11+
NotificationTypeVersion: "1",
12+
Templates: [
1313
{
14-
"Language": "en",
15-
"Description": "Other Notifications",
16-
"TemplatePublic": "{{title}}",
17-
"TemplateSensitive": "{{title}}",
18-
"TemplateGrouped": "Other Notifications",
19-
"TemplateLanguage": "mustache",
20-
"Subtitle": "{{description}}"
14+
Language: "en",
15+
Description: "Other Notifications",
16+
TemplatePublic: "{{title}}",
17+
TemplateSensitive: "{{title}}",
18+
TemplateGrouped: "Other Notifications",
19+
TemplateLanguage: "mustache",
20+
Subtitle: "{{description}}"
2121
}
2222
]
2323
};
2424

2525
function fromOdataArrayFormat(objectInArray) {
2626
if (objectInArray === undefined || objectInArray === null || Array.isArray(objectInArray)) {
27-
return objectInArray;
27+
return (objectInArray === undefined || objectInArray === null) ? [] : objectInArray;
2828
} else {
29-
return objectInArray.results;
29+
return (objectInArray.results === undefined || objectInArray.results === null) ? [] : objectInArray.results;
3030
}
3131
}
3232

@@ -63,15 +63,15 @@ async function getNotificationTypes() {
6363
const notificationDestination = await getNotificationDestination();
6464
const response = await executeHttpRequest(notificationDestination, {
6565
url: `${NOTIFICATION_TYPES_API_ENDPOINT}/NotificationTypes?$format=json&$expand=Templates,Actions,DeliveryChannels`,
66-
method: "get",
66+
method: "get"
6767
});
6868
return response.data.d.results;
6969
}
7070

7171
async function createNotificationType(notificationType) {
7272
const notificationDestination = await getNotificationDestination();
7373
const csrfHeaders = await buildHeadersForDestination(notificationDestination, {
74-
url: NOTIFICATION_TYPES_API_ENDPOINT,
74+
url: NOTIFICATION_TYPES_API_ENDPOINT
7575
});
7676

7777
LOG._warn && LOG.warn(
@@ -82,15 +82,15 @@ async function createNotificationType(notificationType) {
8282
url: `${NOTIFICATION_TYPES_API_ENDPOINT}/NotificationTypes`,
8383
method: "post",
8484
data: notificationType,
85-
headers: csrfHeaders,
85+
headers: csrfHeaders
8686
});
8787
return response.data?.d ?? response;
8888
}
8989

9090
async function updateNotificationType(id, notificationType) {
9191
const notificationDestination = await getNotificationDestination();
9292
const csrfHeaders = await buildHeadersForDestination(notificationDestination, {
93-
url: NOTIFICATION_TYPES_API_ENDPOINT,
93+
url: NOTIFICATION_TYPES_API_ENDPOINT
9494
});
9595

9696
LOG._info && LOG.info(
@@ -101,15 +101,15 @@ async function updateNotificationType(id, notificationType) {
101101
url: `${NOTIFICATION_TYPES_API_ENDPOINT}/NotificationTypes(guid'${id}')`,
102102
method: "patch",
103103
data: notificationType,
104-
headers: csrfHeaders,
104+
headers: csrfHeaders
105105
});
106106
return response.status;
107107
}
108108

109109
async function deleteNotificationType(notificationType) {
110110
const notificationDestination = await getNotificationDestination();
111111
const csrfHeaders = await buildHeadersForDestination(notificationDestination, {
112-
url: NOTIFICATION_TYPES_API_ENDPOINT,
112+
url: NOTIFICATION_TYPES_API_ENDPOINT
113113
});
114114

115115
LOG._info && LOG.info(
@@ -119,16 +119,12 @@ async function deleteNotificationType(notificationType) {
119119
const response = await executeHttpRequest(notificationDestination, {
120120
url: `${NOTIFICATION_TYPES_API_ENDPOINT}/NotificationTypes(guid'${notificationType.NotificationTypeId}')`,
121121
method: "delete",
122-
headers: csrfHeaders,
122+
headers: csrfHeaders
123123
});
124124
return response.status;
125125
}
126126

127127
function _createChannelsMap(channels) {
128-
if (channels === null || channels === undefined) {
129-
return {};
130-
}
131-
132128
const channelMap = {};
133129

134130
channels.forEach((channel) => {
@@ -240,9 +236,9 @@ function isNotificationTypeEqual(oldNotificationType, newNotificationType) {
240236

241237
return (
242238
oldNotificationType.IsGroupable == newNotificationType.IsGroupable &&
243-
areTemplatesEqual(oldNotificationType.Templates.results, fromOdataArrayFormat(newNotificationType.Templates)) &&
244-
areActionsEqual(oldNotificationType.Actions.results, fromOdataArrayFormat(newNotificationType.Actions)) &&
245-
areDeliveryChannelsEqual(oldNotificationType.DeliveryChannels.results, fromOdataArrayFormat(newNotificationType.DeliveryChannels))
239+
areTemplatesEqual(fromOdataArrayFormat(oldNotificationType.Templates), fromOdataArrayFormat(newNotificationType.Templates)) &&
240+
areActionsEqual(fromOdataArrayFormat(oldNotificationType.Actions), fromOdataArrayFormat(newNotificationType.Actions)) &&
241+
areDeliveryChannelsEqual(fromOdataArrayFormat(oldNotificationType.DeliveryChannels), fromOdataArrayFormat(newNotificationType.DeliveryChannels))
246242
);
247243
}
248244

@@ -262,9 +258,7 @@ async function processNotificationTypes(notificationTypesJSON) {
262258
}
263259

264260
if (!existingType.NotificationTypeKey.startsWith(`${prefix}/`)) {
265-
LOG._info && LOG.info(
266-
`Skipping Notification Type of other application: ${existingType.NotificationTypeKey}.`
267-
);
261+
LOG._info && LOG.info(`Skipping Notification Type of other application: ${existingType.NotificationTypeKey}.`);
268262
continue;
269263
}
270264

lib/notifications.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
const { buildHeadersForDestination } = require("@sap-cloud-sdk/connectivity");
2+
const { executeHttpRequest } = require("@sap-cloud-sdk/http-client");
3+
const { getNotificationDestination } = require("./utils");
4+
const LOG = cds.log('notifications');
5+
const NOTIFICATIONS_API_ENDPOINT = "v2/Notification.svc";
6+
7+
async function postNotification(notificationData) {
8+
const notificationDestination = await getNotificationDestination();
9+
const csrfHeaders = await buildHeadersForDestination(notificationDestination, {
10+
url: NOTIFICATIONS_API_ENDPOINT,
11+
});
12+
13+
try {
14+
LOG._info && LOG.info(
15+
`Sending notification of key: ${notificationData.NotificationTypeKey} and version: ${notificationData.NotificationTypeVersion}`
16+
);
17+
await executeHttpRequest(notificationDestination, {
18+
url: `${NOTIFICATIONS_API_ENDPOINT}/Notifications`,
19+
method: "post",
20+
data: notificationData,
21+
headers: csrfHeaders,
22+
});
23+
} catch (err) {
24+
const message = err.response.data?.error?.message?.value ?? err.response.message;
25+
const error = new cds.error(message);
26+
27+
if (String(err.response?.status).match(/^4\d\d$/) && err.response?.status !== 429) {
28+
error.unrecoverable = true;
29+
}
30+
31+
throw error;
32+
}
33+
}
34+
35+
module.exports = {
36+
postNotification
37+
};

lib/utils.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ const messages = {
1818
PROPERTIES_IS_NOT_OBJECT: "Properties is not an object.",
1919
NAVIGATION_IS_NOT_OBJECT: "Navigation is not an object.",
2020
PAYLOAD_IS_NOT_OBJECT: "Payload is not an object.",
21-
EMPTY_OBJECT_FOR_NOTIFY: "Empty object is passed a single parameter to notify function."
21+
EMPTY_OBJECT_FOR_NOTIFY: "Empty object is passed a single parameter to notify function.",
22+
NO_OBJECT_FOR_NOTIFY: "An object must be passed to notify function."
2223
};
2324

2425
function validateNotificationTypes(notificationTypes) {
@@ -199,6 +200,11 @@ function buildCustomNotification(notificationData) {
199200
function buildNotification(notificationData) {
200201
let notification;
201202

203+
if(notificationData === undefined || notificationData === null) {
204+
LOG._warn && LOG.warn(messages.NO_OBJECT_FOR_NOTIFY);
205+
return;
206+
}
207+
202208
if (Object.keys(notificationData).length === 0) {
203209
LOG._warn && LOG.warn(messages.EMPTY_OBJECT_FOR_NOTIFY);
204210
return;

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
"lodash": "4.17.21"
2121
},
2222
"devDependencies": {
23-
"jest": "^29.7.0"
23+
"jest": "^29.7.0",
24+
"chai": "^4.3.10"
2425
},
2526
"scripts": {
2627
"lint": "npx eslint .",
27-
"test": "npx jest --silent",
28+
"test": "npx jest",
2829
"test-with-coverage": "npx jest --coverage"
2930
},
3031
"cds": {

srv/notifyToRest.js

Lines changed: 4 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
const cds = require('@sap/cds');
2-
const LOG = cds.log('notifications');
31
const NotificationService = require('./service');
4-
const NOTIFICATIONS_API_ENDPOINT = "v2/Notification.svc";
5-
const { executeHttpRequest } = require("@sap-cloud-sdk/http-client");
6-
const { buildHeadersForDestination } = require("@sap-cloud-sdk/connectivity");
7-
const { getNotificationDestination, buildNotification } = require("../lib/utils");
2+
const { buildNotification } = require("../lib/utils");
3+
const { postNotification } = require('../lib/notifications');
84

95
module.exports = class NotifyToRest extends NotificationService {
106
async init() {
@@ -14,30 +10,11 @@ module.exports = class NotifyToRest extends NotificationService {
1410

1511
this.on('postNotificationEvent', async function(req) {
1612
const { data } = req;
17-
const notificationDestination = await getNotificationDestination();
18-
const csrfHeaders = await buildHeadersForDestination(notificationDestination, {
19-
url: NOTIFICATIONS_API_ENDPOINT,
20-
});
2113

2214
try {
23-
LOG._info && LOG.info(
24-
`Sending notification of key: ${data.NotificationTypeKey} and version: ${data.NotificationTypeVersion}`
25-
);
26-
await executeHttpRequest(notificationDestination, {
27-
url: `${NOTIFICATIONS_API_ENDPOINT}/Notifications`,
28-
method: "post",
29-
data: data,
30-
headers: csrfHeaders,
31-
});
15+
await postNotification(data);
3216
} catch (err) {
33-
const message = err.response.data?.error?.message?.value ?? err.response.message;
34-
const error = new cds.error(message);
35-
36-
if (String(err.response?.status).match(/^4\d\d$/) && err.response?.status !== 429) {
37-
error.unrecoverable = true;
38-
}
39-
40-
throw error;
17+
throw err;
4118
}
4219
});
4320
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// import required modules and functions
2+
const cds = require("@sap/cds");
3+
const { validateNotificationTypes, readFile } = require("../../lib/utils");
4+
const { processNotificationTypes } = require("../../lib/notificationTypes");
5+
const { setGlobalLogLevel } = require("@sap-cloud-sdk/util");
6+
const assert = require("chai");
7+
8+
jest.mock("../../lib/utils");
9+
jest.mock("../../lib/notificationTypes");
10+
jest.mock("@sap-cloud-sdk/util");
11+
12+
const contentDeployment = require("../../lib/content-deployment");
13+
14+
describe("contentDeployment", () => {
15+
beforeEach(() => {
16+
jest.clearAllMocks();
17+
});
18+
19+
test("Given valid notification types | When Deploy is called | Then process is called", async () => {
20+
setGlobalLogLevel.mockImplementation(() => undefined);
21+
readFile.mockImplementation(() => []);
22+
validateNotificationTypes.mockImplementation(() => true);
23+
processNotificationTypes.mockImplementation(() => Promise.resolve());
24+
25+
await contentDeployment.deployNotificationTypes();
26+
27+
console.log(setGlobalLogLevel.mock.calls);
28+
assert.expect(setGlobalLogLevel.mock.calls[0][0]).to.be.equal("error");
29+
assert.expect(readFile.mock.calls[0][0]).to.be.equal(cds.env?.requires?.notifications?.types);
30+
assert.expect(validateNotificationTypes.mock.calls[0][0]).to.be.deep.equal([]);
31+
assert.expect(processNotificationTypes.mock.calls[0][0]).to.be.deep.equal([]);
32+
});
33+
34+
test("Given invalid notification types | When Deploy is called | Then process is called", async () => {
35+
setGlobalLogLevel.mockImplementation(() => undefined);
36+
readFile.mockImplementation(() => []);
37+
validateNotificationTypes.mockImplementation(() => false);
38+
processNotificationTypes.mockImplementation(() => Promise.resolve());
39+
40+
await contentDeployment.deployNotificationTypes();
41+
42+
console.log(setGlobalLogLevel.mock.calls);
43+
assert.expect(setGlobalLogLevel.mock.calls[0][0]).to.be.equal("error");
44+
assert.expect(readFile.mock.calls[0][0]).to.be.equal(cds.env?.requires?.notifications?.types);
45+
assert.expect(validateNotificationTypes.mock.calls[0][0]).to.be.deep.equal([]);
46+
assert.expect(processNotificationTypes.mock.calls[0]).to.be.deep.equal(undefined);
47+
});
48+
});

0 commit comments

Comments
 (0)