From c3329e93ec816bc29b8e419a8d002a1882151a93 Mon Sep 17 00:00:00 2001 From: Luca Cavallaro Date: Fri, 19 Jan 2024 10:53:24 +0100 Subject: [PATCH] [IOPID-1290] Track "io.citizen-auth.reset_email_validation" event --- .../__tests__/handler.spec.ts | 31 ++++++++- SanitizeProfileEmail/handler.ts | 22 +++++-- SanitizeProfileEmail/index.ts | 4 +- package.json | 2 +- yarn.lock | 66 ++++++++++++++++++- 5 files changed, 115 insertions(+), 10 deletions(-) diff --git a/SanitizeProfileEmail/__tests__/handler.spec.ts b/SanitizeProfileEmail/__tests__/handler.spec.ts index c6d7cfd2..3410fa19 100644 --- a/SanitizeProfileEmail/__tests__/handler.spec.ts +++ b/SanitizeProfileEmail/__tests__/handler.spec.ts @@ -2,6 +2,8 @@ import { describe, it, jest } from "@jest/globals"; import { Container } from "@azure/cosmos"; +import * as ai from "applicationinsights"; + import * as TE from "fp-ts/lib/TaskEither"; import * as E from "fp-ts/lib/Either"; import * as O from "fp-ts/lib/Option"; @@ -17,6 +19,8 @@ import { EmailString, FiscalCode } from "@pagopa/ts-commons/lib/strings"; import { aFiscalCode, aRetrievedProfile } from "../../__mocks__/mocks"; import { ProfileToSanitize, sanitizeProfileEmail } from "../handler"; +import { hashFiscalCode } from "@pagopa/ts-commons/lib/hash"; +import { ContextTagKeys } from "applicationinsights/out/Declarations/Contracts"; const fiscalCodes = { TO_SANITIZE: "BBBBBB20B20B222B" as FiscalCode, @@ -34,6 +38,10 @@ const mocks = { fiscalCodes }; +jest.mock("applicationinsights"); + +const telemetryClient = jest.mocked(ai.defaultClient); + jest.mock("@pagopa/io-functions-commons/dist/src/models/profile"); const MockedProfileModel = jest.mocked(ProfileModel); @@ -122,7 +130,11 @@ describe("Given a list a profiles to be sanitized with their duplicated e-mail a await Promise.all( profiles.map(p => - sanitizeProfileEmail(p)({ profileModel, logger: ConsoleLogger })() + sanitizeProfileEmail(p)({ + profileModel, + logger: ConsoleLogger, + telemetryClient + })() ) ); @@ -133,6 +145,17 @@ describe("Given a list a profiles to be sanitized with their duplicated e-mail a fiscalCode: mocks.fiscalCodes.TO_SANITIZE }) ); + + expect(telemetryClient.trackEvent).toBeCalledTimes(1); + expect(telemetryClient.trackEvent).toBeCalledWith( + expect.objectContaining({ + name: "io.citizen-auth.reset_email_validation", + tagOverrides: { + samplingEnabled: "false", + "ai.user.id": hashFiscalCode(mocks.fiscalCodes.TO_SANITIZE) + } + }) + ); }); it("should fail without creating new profile versions if there are errors retrieving the eligible profiles", async () => { @@ -141,7 +164,8 @@ describe("Given a list a profiles to be sanitized with their duplicated e-mail a fiscalCode: mocks.fiscalCodes.ERROR })({ profileModel, - logger: ConsoleLogger + logger: ConsoleLogger, + telemetryClient })(); if (E.isLeft(result)) { expect(MockedProfileModel.prototype.update).toBeCalledTimes(0); @@ -166,7 +190,8 @@ describe("Given a list a profiles to be sanitized with their duplicated e-mail a fiscalCode })({ profileModel, - logger: ConsoleLogger + logger: ConsoleLogger, + telemetryClient })(); if (E.isRight(result)) { expect(MockedProfileModel.prototype.update).toHaveBeenCalledWith( diff --git a/SanitizeProfileEmail/handler.ts b/SanitizeProfileEmail/handler.ts index e6078a73..b0689f1b 100644 --- a/SanitizeProfileEmail/handler.ts +++ b/SanitizeProfileEmail/handler.ts @@ -1,6 +1,9 @@ +import { TelemetryClient } from "applicationinsights"; + import * as t from "io-ts"; import { EmailString, FiscalCode } from "@pagopa/ts-commons/lib/strings"; +import { hashFiscalCode } from "@pagopa/ts-commons/lib/hash"; import * as RTE from "fp-ts/lib/ReaderTaskEither"; import * as TE from "fp-ts/lib/TaskEither"; @@ -56,7 +59,7 @@ const OPT_OUT_EMAIL_SWITCH_DATE = 1625781600; const updateProfile = (profile: RetrievedProfile) => ( r: IProfileModel -): TE.TaskEither => +): TE.TaskEither => pipe( r.profileModel.update({ ...profile, @@ -67,10 +70,20 @@ const updateProfile = (profile: RetrievedProfile) => ( : profile.isEmailEnabled, isEmailValidated: false }), - TE.mapLeft(flow(cosmosErrorsToString, Error)), - TE.map(() => void 0) + TE.mapLeft(flow(cosmosErrorsToString, Error)) ); +const trackResetEmailValidationEvent = ( + profile: Pick +) => (r: { readonly telemetryClient: TelemetryClient }) => (): void => + r.telemetryClient.trackEvent({ + name: "io.citizen-auth.reset_email_validation", + tagOverrides: { + "ai.user.id": hashFiscalCode(profile.fiscalCode), + samplingEnabled: "false" + } + }); + export const sanitizeProfileEmail = flow( getProfileForUpdate, RTE.chainFirstW(maybe => @@ -83,7 +96,8 @@ export const sanitizeProfileEmail = flow( O.map( flow( updateProfile, - RTE.chainFirstW(() => L.debugRTE("profile updated")) + RTE.chainFirstW(() => L.debugRTE("profile updated")), + RTE.chainFirstReaderIOKW(trackResetEmailValidationEvent) ) ), O.getOrElse(() => RTE.right(void 0)) diff --git a/SanitizeProfileEmail/index.ts b/SanitizeProfileEmail/index.ts index 3a48fce4..b3f1f75f 100644 --- a/SanitizeProfileEmail/index.ts +++ b/SanitizeProfileEmail/index.ts @@ -8,6 +8,7 @@ import { import { cosmosdbInstance } from "../utils/cosmosdb"; +import { initTelemetryClient } from "../utils/appinsights"; import { ProfileToSanitize, sanitizeProfileEmail } from "./handler"; const profilesContainer = cosmosdbInstance.container(PROFILE_COLLECTION_NAME); @@ -20,5 +21,6 @@ const createSanitizeProfileEmailsFunction = azureFunction( export default createSanitizeProfileEmailsFunction({ inputDecoder: ProfileToSanitize, - profileModel + profileModel, + telemetryClient: initTelemetryClient() }); diff --git a/package.json b/package.json index a50ba836..00c3c803 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "@pagopa/io-backend-session-sdk": "x", "@pagopa/io-functions-commons": "^28.13.0", "@pagopa/logger": "^1.0.1", - "@pagopa/ts-commons": "^11.0.0", + "@pagopa/ts-commons": "^12.5.0", "@types/archiver": "^3.1.1", "@types/randomstring": "^1.1.6", "applicationinsights": "^1.8.10", diff --git a/yarn.lock b/yarn.lock index 7a097fac..86be771b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1615,6 +1615,24 @@ semver "^7.3.7" validator "^13.7.0" +"@pagopa/ts-commons@^12.5.0": + version "12.5.0" + resolved "https://registry.yarnpkg.com/@pagopa/ts-commons/-/ts-commons-12.5.0.tgz#382f310b3aaf752e9a1cc31b46b2f4fd4a27c533" + integrity sha512-FAXqMLvNtt6Aq0BTHjQ1RFfvcs1plv20Iyq+UCmDHQTt8H7ThdLK7KoIqN1oBLkX9Ex+Nm9s77G2k2Df9BF9/Q== + dependencies: + abort-controller "^3.0.0" + agentkeepalive "^4.1.4" + applicationinsights "^1.8.10" + fp-ts "2.14.0" + io-ts "2.2.20" + jose "^4.11.2" + json-set-map "^1.1.2" + jsonwebtoken "^9.0.1" + node-fetch "^2.6.0" + semver "^7.3.7" + ulid "^2.3.0" + validator "^13.7.0" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -5358,6 +5376,11 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== +fp-ts@2.14.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.14.0.tgz#97ac3d9f002dcd02f93ca1269ae14a7fcb805582" + integrity sha512-QLagLSYAgMA00pZzUzeksH/78Sd14y7+Gc2A8Yaja3/IpGOFMdm/gYBuDMxYqLsJ58iT5lz+bJb953RAeFfp1A== + fp-ts@^2.10.5, fp-ts@^2.11.0, fp-ts@^2.11.1: version "2.13.1" resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-2.13.1.tgz#1bf2b24136cca154846af16752dc29e8fa506f2a" @@ -6135,7 +6158,7 @@ invert-kv@^1.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" integrity sha512-xgs2NH9AE66ucSq4cNG1nhSFghr5l6tdL15Pk+jl46bmmBapgoaY/AacXyaDznAqmGL99TiLSQgO/XazFSKYeQ== -io-ts@^2.2.16: +io-ts@2.2.20, io-ts@^2.2.16: version "2.2.20" resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-2.2.20.tgz#be42b75f6668a2c44f706f72ee6e4c906777c7f5" integrity sha512-Rq2BsYmtwS5vVttie4rqrOCIfHCS9TgpRLFpKQCM1wZBBRY9nWVGmEvm2FnDbSE2un1UE39DvFpTR5UL47YDcA== @@ -7552,6 +7575,22 @@ jsonwebtoken@^9.0.0: ms "^2.1.1" semver "^7.3.8" +jsonwebtoken@^9.0.1: + version "9.0.2" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" + integrity sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^7.5.4" + jsprim@^1.2.2: version "1.4.2" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" @@ -7948,6 +7987,11 @@ lodash.get@^4.0.0, lodash.get@^4.3.0, lodash.get@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ== +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w== + lodash.isarguments@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" @@ -7958,16 +8002,31 @@ lodash.isarray@^3.0.0: resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" integrity sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ== +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg== + lodash.isequal@^4.0.0, lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== + lodash.ismatch@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" integrity sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g== +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw== + lodash.isplainobject@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" @@ -7997,6 +8056,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"