Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#IP-84] Change strict configuration to true #157

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions HandleNHNotificationCallActivity/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ const success = () =>
kind: "SUCCESS"
});

const assertNever = (x: never): never => {
throw new Error(`Unexpected object: ${toString(x)}`);
};
// tslint:disable:no-any
const createUnexpecterError = (x: any): Error =>
new Error(`Unexpected object: ${toString(x)}`);

const telemetryClient = initTelemetryClient();

Expand Down Expand Up @@ -125,7 +125,7 @@ export const getCallNHServiceActivityHandler = (
return failure(e.message);
});
default:
assertNever(message);
throw createUnexpecterError(message);
}
})
.fold<ActivityResult>(err => err, _ => success())
Expand Down
17 changes: 12 additions & 5 deletions StartEmailValidationProcess/__tests__/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
context as contextMock,
mockStartNew
} from "../../__mocks__/durable-functions";
import { aRetrievedProfile } from "../../__mocks__/mocks";
import {
aRetrievedProfile,
aRetrievedProfileWithEmail
} from "../../__mocks__/mocks";
import { StartEmailValidationProcessHandler } from "../handler";
import * as orchUtil from "../orchestrators";

Expand All @@ -28,7 +31,9 @@ describe("StartEmailValidationProcessHandler", () => {
it("should start the orchestrator with the right input and return an accepted response", async () => {
const profileModelMock = {
findLastVersionByModelId: jest.fn(() =>
taskEither.of(some({ ...aRetrievedProfile, isEmailValidated: false }))
taskEither.of(
some({ ...aRetrievedProfileWithEmail, isEmailValidated: false })
)
)
};
mockStartNew.mockImplementationOnce(() => Promise.resolve("start"));
Expand All @@ -37,7 +42,7 @@ describe("StartEmailValidationProcessHandler", () => {

const result = await handler(
contextMock as any,
aRetrievedProfile.fiscalCode
aRetrievedProfileWithEmail.fiscalCode
);

expect(result.kind).toBe("IResponseSuccessAccepted");
Expand All @@ -46,7 +51,9 @@ describe("StartEmailValidationProcessHandler", () => {
it("should not start a new orchestrator if there is an already running orchestrator and return an accepted response", async () => {
const profileModelMock = {
findLastVersionByModelId: jest.fn(() =>
taskEither.of(some({ ...aRetrievedProfile, isEmailValidated: false }))
taskEither.of(
some({ ...aRetrievedProfileWithEmail, isEmailValidated: false })
)
)
};

Expand All @@ -59,7 +66,7 @@ describe("StartEmailValidationProcessHandler", () => {

const result = await handler(
contextMock as any,
aRetrievedProfile.fiscalCode
aRetrievedProfileWithEmail.fiscalCode
);
expect(mockStartNew).not.toHaveBeenCalled();

Expand Down
7 changes: 7 additions & 0 deletions StartEmailValidationProcess/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,13 @@ export function StartEmailValidationProcessHandler(

const { email } = existingProfile;

if (email === undefined) {
return ResponseErrorValidation(
"Validation error",
"The email is missing for the profile with the provided fiscal code"
);
}

// Start a orchestrator that handles the email validation process.
context.log.verbose(`${logPrefix}|Starting the email validation process`);
const emailValidationProcessOrchestartorInput = EmailValidationProcessOrchestratorInput.encode(
Expand Down
2 changes: 1 addition & 1 deletion UpdateProfile/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export function UpdateProfileHandler(
const profile = apiProfileToProfile(
profilePayload,
fiscalCode,
emailChanged ? false : existingProfile.isEmailValidated
emailChanged ? false : existingProfile.isEmailValidated === true
);

// User inbox and webhook must be enabled after accepting the ToS for the first time
Expand Down
229 changes: 128 additions & 101 deletions UpsertedProfileOrchestrator/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,125 +79,84 @@ export const getUpsertedProfileOrchestratorHandler = (params: {
updatedAt
} = upsertedProfileOrchestratorInput;

const profileOperation = oldProfile !== undefined ? "UPDATED" : "CREATED";
const isInboxEnabled = newProfile.isInboxEnabled === true;

// Check if the profile email is changed
const isProfileEmailChanged =
profileOperation === "UPDATED" && newProfile.email !== oldProfile.email;
if (isProfileEmailChanged) {
try {
const { fiscalCode, email } = newProfile;
if (oldProfile !== undefined) {
const profileOperation = "UPDATED";

// Start a sub-orchestrator that handles the email validation process.
// From the caller point it is like a normal activity.
context.log.verbose(
`${logPrefix}|Email changed, starting the email validation process`
);
const emailValidationProcessOrchestartorInput = EmailValidationProcessOrchestratorInput.encode(
{
email,
fiscalCode
// Check if the profile email is changed
const isProfileEmailChanged = newProfile.email !== oldProfile.email;
if (isProfileEmailChanged) {
try {
const { fiscalCode, email } = newProfile;

// Start a sub-orchestrator that handles the email validation process.
// From the caller point it is like a normal activity.
context.log.verbose(
`${logPrefix}|Email changed, starting the email validation process`
);

if (email === undefined) {
throw new Error(
"The email is missing for the profile with the provided fiscal code"
);
}
);

const emailValidationProcessOrchestartorResultJson = yield context.df.callSubOrchestratorWithRetry(
"EmailValidationProcessOrchestrator",
retryOptions,
emailValidationProcessOrchestartorInput
);
const emailValidationProcessOrchestartorInput = EmailValidationProcessOrchestratorInput.encode(
{
email,
fiscalCode
}
);

const errorOrEmailValidationProcessOrchestartorResult = EmailValidationProcessOrchestratorResult.decode(
emailValidationProcessOrchestartorResultJson
);
const emailValidationProcessOrchestartorResultJson = yield context.df.callSubOrchestratorWithRetry(
"EmailValidationProcessOrchestrator",
retryOptions,
emailValidationProcessOrchestartorInput
);

if (isLeft(errorOrEmailValidationProcessOrchestartorResult)) {
context.log.error(
`${logPrefix}|Error decoding sub-orchestrator result|ERROR=${readableReport(
errorOrEmailValidationProcessOrchestartorResult.value
)}`
const errorOrEmailValidationProcessOrchestartorResult = EmailValidationProcessOrchestratorResult.decode(
emailValidationProcessOrchestartorResultJson
);
} else {
const emailValidationProcessOrchestartorResult =
errorOrEmailValidationProcessOrchestartorResult.value;

if (emailValidationProcessOrchestartorResult.kind === "FAILURE") {
if (isLeft(errorOrEmailValidationProcessOrchestartorResult)) {
context.log.error(
`${logPrefix}|Sub-orchestrator error|ERROR=${emailValidationProcessOrchestartorResult.reason}`
`${logPrefix}|Error decoding sub-orchestrator result|ERROR=${readableReport(
errorOrEmailValidationProcessOrchestartorResult.value
)}`
);
return false;
}
} else {
const emailValidationProcessOrchestartorResult =
errorOrEmailValidationProcessOrchestartorResult.value;

context.log.verbose(
`${logPrefix}|Email verification process completed sucessfully`
if (emailValidationProcessOrchestartorResult.kind === "FAILURE") {
context.log.error(
`${logPrefix}|Sub-orchestrator error|ERROR=${emailValidationProcessOrchestartorResult.reason}`
);
return false;
}

context.log.verbose(
`${logPrefix}|Email verification process completed sucessfully`
);
}
} catch (e) {
context.log.error(
`${logPrefix}|Email verification process max retry exceeded|ERROR=${e}`
);
}
} catch (e) {
context.log.error(
`${logPrefix}|Email verification process max retry exceeded|ERROR=${e}`
);
}
}

// Send welcome messages to the user
const isInboxEnabled = newProfile.isInboxEnabled === true;
const hasOldProfileWithInboxDisabled =
profileOperation === "UPDATED" && oldProfile.isInboxEnabled === false;

const hasJustEnabledInbox =
isInboxEnabled &&
(profileOperation === "CREATED" || hasOldProfileWithInboxDisabled);

context.log.verbose(
`${logPrefix}|OPERATION=${profileOperation}|INBOX_ENABLED=${isInboxEnabled}|INBOX_JUST_ENABLED=${hasJustEnabledInbox}`
);

if (hasJustEnabledInbox) {
yield context.df.callActivityWithRetry(
"SendWelcomeMessagesActivity",
retryOptions,
{
messageKind: "WELCOME",
profile: newProfile
} as SendWelcomeMessageActivityInput
);
yield context.df.callActivityWithRetry(
"SendWelcomeMessagesActivity",
retryOptions,
{
messageKind: "HOWTO",
profile: newProfile
} as SendWelcomeMessageActivityInput
// Send welcome messages to the user
const hasJustEnabledInbox =
isInboxEnabled && oldProfile.isInboxEnabled === false;
context.log.verbose(
`${logPrefix}|OPERATION=${profileOperation}|INBOX_ENABLED=${isInboxEnabled}|INBOX_JUST_ENABLED=${hasJustEnabledInbox}`
);
if (params.sendCashbackMessage) {
yield context.df.callActivityWithRetry(
"SendWelcomeMessagesActivity",
retryOptions,
{
messageKind: "CASHBACK",
profile: newProfile
} as SendWelcomeMessageActivityInput
);
if (hasJustEnabledInbox) {
yield* sendWelcomeMessages(context, retryOptions, newProfile, params);
}
}

// Update subscriptions feed
if (profileOperation === "CREATED") {
// When a profile get created we add an entry to the profile subscriptions
context.log.verbose(
`${logPrefix}|Calling UpdateSubscriptionsFeedActivity|OPERATION=SUBSCRIBED`
);
yield context.df.callActivityWithRetry(
"UpdateSubscriptionsFeedActivity",
retryOptions,
{
fiscalCode: newProfile.fiscalCode,
operation: "SUBSCRIBED",
subscriptionKind: "PROFILE",
updatedAt: updatedAt.getTime(),
version: newProfile.version
} as UpdateServiceSubscriptionFeedActivityInput
);
} else {
// When the profile gets updates, we extract the services that have been
// blocked and unblocked during this profile update.
// Blocked services get mapped to unsubscribe events, while unblocked ones
Expand Down Expand Up @@ -245,7 +204,75 @@ export const getUpsertedProfileOrchestratorHandler = (params: {
} as UpdateServiceSubscriptionFeedActivityInput
);
}
} else {
const profileOperation = "CREATED";

// Send welcome messages to the user
const hasJustEnabledInbox = isInboxEnabled;
context.log.verbose(
`${logPrefix}|OPERATION=${profileOperation}|INBOX_ENABLED=${isInboxEnabled}|INBOX_JUST_ENABLED=${hasJustEnabledInbox}`
);
if (hasJustEnabledInbox) {
yield* sendWelcomeMessages(context, retryOptions, newProfile, params);
}
// Update subscriptions feed
// When a profile get created we add an entry to the profile subscriptions
context.log.verbose(
`${logPrefix}|Calling UpdateSubscriptionsFeedActivity|OPERATION=SUBSCRIBED`
);
yield context.df.callActivityWithRetry(
"UpdateSubscriptionsFeedActivity",
retryOptions,
{
fiscalCode: newProfile.fiscalCode,
operation: "SUBSCRIBED",
subscriptionKind: "PROFILE",
updatedAt: updatedAt.getTime(),
version: newProfile.version
} as UpdateServiceSubscriptionFeedActivityInput
);
}

return true;
};

/**
* Send Welcome messages to profile owner. Triggers the proper sendMessage activity required by input handelr parameters.
* @param context - the orchestrator context
* @param retryOptions - the retry configuration
* @param newProfile - the new profile
* @param params - the handler params
*/
function* sendWelcomeMessages(
context: IOrchestrationFunctionContext,
retryOptions: df.RetryOptions,
newProfile: RetrievedProfile,
params: { sendCashbackMessage: boolean }
): Generator<unknown, void, unknown> {
yield context.df.callActivityWithRetry(
"SendWelcomeMessagesActivity",
retryOptions,
{
messageKind: "WELCOME",
profile: newProfile
} as SendWelcomeMessageActivityInput
);
yield context.df.callActivityWithRetry(
"SendWelcomeMessagesActivity",
retryOptions,
{
messageKind: "HOWTO",
profile: newProfile
} as SendWelcomeMessageActivityInput
);
if (params.sendCashbackMessage) {
yield context.df.callActivityWithRetry(
"SendWelcomeMessagesActivity",
retryOptions,
{
messageKind: "CASHBACK",
profile: newProfile
} as SendWelcomeMessageActivityInput
);
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@types/azure-sb": "^0.0.37",
"@types/documentdb": "^1.10.5",
"@types/express": "^4.16.0",
"@types/node-fetch": "^2.5.10",
"@types/html-to-text": "^1.4.31",
"@types/jest": "^24.0.15",
"@types/lolex": "^3.1.1",
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"outDir": "dist",
"rootDir": ".",
"sourceMap": true,
"strict": false,
"strict": true,
"resolveJsonModule": true
},
"exclude": ["__mocks__"]
Expand Down
9 changes: 6 additions & 3 deletions utils/__tests__/notification.keepalive.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ describe("NotificationHubService", () => {
message_id: "bar",
title: "beef"
}).run();
expect(responseSpy).toHaveBeenCalledWith(
parseInt(process.env.FETCH_KEEPALIVE_MAX_SOCKETS, 10)
);

const keepalive =
process.env.FETCH_KEEPALIVE_MAX_SOCKETS === undefined
? "40"
: process.env.FETCH_KEEPALIVE_MAX_SOCKETS;
expect(responseSpy).toHaveBeenCalledWith(parseInt(keepalive, 10));
});
});
Loading