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

[#IOPID-1192] added optional field to endpoint notify-login #288

Merged
merged 4 commits into from
Dec 19, 2023
Merged
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
57 changes: 56 additions & 1 deletion NoticeLoginEmailOrchestrator/__tests__/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ const aValidOrchestratorInput: OrchestratorInput = {
identity_provider: "idp" as NonEmptyString,
ip_address: anIPAddress,
name: "foo" as NonEmptyString,
device_name: "aDevice" as NonEmptyString
device_name: "aDevice" as NonEmptyString,
is_email_validated: true
};
const mockCallActivityFunction = jest.fn();
const mockGetInput = jest.fn().mockReturnValue(aValidOrchestratorInput);
Expand Down Expand Up @@ -125,4 +126,58 @@ describe("NoticeLoginEmailOrchestratorHandler", () => {
fail();
}
});

it.each`
scenario | value
${"the user doesn't have a validated email"} | ${false}
${"the api was called without the is_email_validated parameter"} | ${undefined}
`("should ignore magic_link retrieval if $scenario", ({ value }) => {
mockGetInput.mockReturnValueOnce({
...aValidOrchestratorInput,
is_email_validated: value
});

mockCallActivityFunction.mockReturnValueOnce({
kind: "SUCCESS",
value: { geo_location: "Rome" as NonEmptyString }
});

mockCallActivityFunction.mockReturnValueOnce({
kind: "SUCCESS"
});
const orchestratorHandler = getNoticeLoginEmailOrchestratorHandler(
contextMockWithDf as any
);

const result = consumeGenerator(orchestratorHandler);

// we only call 2 activities because the user doesn't have a validated email
expect(mockCallActivityFunction).toHaveBeenCalledTimes(2);

expect(mockCallActivityFunction).toHaveBeenNthCalledWith(
1,
"GetGeoLocationDataActivity",
someRetryOptions,
{
ip_address: anIPAddress
}
);
expect(mockCallActivityFunction).toHaveBeenNthCalledWith(
2,
"SendTemplatedLoginEmailActivity",
someRetryOptions,
{
date_time: aDate.getTime(),
name: "foo",
ip_address: anIPAddress,
//since we ignored the magic_link retrieval, this MUST be undefined
magic_link: undefined,
identity_provider: "idp",
geo_location: "Rome",
email: "example@example.com",
device_name: "aDevice"
}
);
expect(OrchestratorSuccessResult.is(result)).toEqual(true);
});
});
75 changes: 45 additions & 30 deletions NoticeLoginEmailOrchestrator/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import * as df from "durable-functions";
import * as E from "fp-ts/lib/Either";
import { readableReportSimplified } from "@pagopa/ts-commons/lib/reporters";
import { DateFromTimestamp } from "@pagopa/ts-commons/lib/dates";
import { withDefault } from "@pagopa/ts-commons/lib/types";
import {
ActivityInput as SendTemplatedLoginEmailActivityInput,
ActivityResultSuccess as SendTemplatedLoginEmailActivityResultSuccess
Expand All @@ -36,7 +37,8 @@ export const OrchestratorInput = t.intersection([
name: NonEmptyString
}),
t.partial({
device_name: NonEmptyString
device_name: NonEmptyString,
is_email_validated: withDefault(t.boolean, false)
})
]);

Expand Down Expand Up @@ -97,7 +99,8 @@ export const getNoticeLoginEmailOrchestratorHandler = function*(
date_time,
device_name,
ip_address,
identity_provider
identity_provider,
is_email_validated
} = orchestratorInput;
/* eslint-enable @typescript-eslint/naming-convention */

Expand Down Expand Up @@ -142,44 +145,56 @@ export const getNoticeLoginEmailOrchestratorHandler = function*(
}
} catch (_) {
// log activity max retry reached
// we let geo_location be undefined and continue to send the base login email template
// we let geo_location be undefined
context.log.error(
`${logPrefix}|GetGeoLocationDataActivity max retry reached`
);
}

context.log.verbose(`${logPrefix}|Starting GetMagicCodeActivity`);
const magicCodeActivityInput = GetMagicCodeActivityInput.encode({
family_name,
fiscal_code,
name
});

// the base template will be sent if:
// 1. the user doesn't have a validated email
// 2. the user does have a validated email but the magic_link couldn't be retrieved
//
// eslint-disable-next-line functional/no-let, @typescript-eslint/naming-convention
let magic_link: NonEmptyString | undefined;
try {
const magicCodeActivityResult = yield context.df.callActivityWithRetry(
"GetMagicCodeActivity",
retryOptions,
magicCodeActivityInput
);
if (is_email_validated) {
context.log.verbose(`${logPrefix}|Starting GetMagicCodeActivity`);
const magicCodeActivityInput = GetMagicCodeActivityInput.encode({
family_name,
fiscal_code,
name
});

const errorOrMagicLinkServiceResponse = GetMagicCodeActivityResult.decode(
magicCodeActivityResult
);
if (E.isRight(errorOrMagicLinkServiceResponse)) {
if (errorOrMagicLinkServiceResponse.right.kind === "SUCCESS") {
magic_link = errorOrMagicLinkServiceResponse.right.value.magic_link;
} else {
context.log.error(
`${logPrefix}|GetMagicCodeActivity failed with ${errorOrMagicLinkServiceResponse.right.reason}`
);
try {
const magicCodeActivityResult = yield context.df.callActivityWithRetry(
"GetMagicCodeActivity",
retryOptions,
magicCodeActivityInput
);

const errorOrMagicLinkServiceResponse = GetMagicCodeActivityResult.decode(
magicCodeActivityResult
);
if (E.isRight(errorOrMagicLinkServiceResponse)) {
if (errorOrMagicLinkServiceResponse.right.kind === "SUCCESS") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (errorOrMagicLinkServiceResponse.right.kind === "SUCCESS") {
const magicLinkServiceResponse = errorOrMagicLinkServiceResponse.right;
if (magicLinkServiceResponse.kind === "SUCCESS") {

magic_link = errorOrMagicLinkServiceResponse.right.value.magic_link;
} else {
context.log.error(
`${logPrefix}|GetMagicCodeActivity failed with ${errorOrMagicLinkServiceResponse.right.reason}`
);
}
}
} catch (_) {
// log activity max retry reached
// we let magic_code be undefined and continue to send the base login email template
context.log.error(
`${logPrefix}|GetMagicCodeActivity max retry reached`
);
}
} catch (_) {
// log activity max retry reached
// we let magic_code be undefined and continue to send the base login email template
context.log.error(`${logPrefix}|GetMagicCodeActivity max retry reached`);
} else {
context.log.verbose(
`${logPrefix}|Ignoring GetMagicCodeActivity. The user doesn't have a validated email`
);
}

context.log.verbose(`${logPrefix}|Starting SendLoginEmailActivity`);
Expand Down
2 changes: 2 additions & 0 deletions openapi/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,8 @@ definitions:
device_name:
type: string
minLength: 1
is_email_validated:
$ref: '#/definitions/IsEmailValidated'
required:
- fiscal_code
- name
Expand Down
2 changes: 2 additions & 0 deletions openapi/index.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,8 @@ definitions:
device_name:
type: string
minLength: 1
is_email_validated:
$ref: '#/definitions/IsEmailValidated'
required:
- fiscal_code
- name
Expand Down