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-215] Allow eu_covid_cert in message content #126

Merged
merged 3 commits into from
Jun 2, 2021
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
2 changes: 1 addition & 1 deletion CreateMessage/__tests__/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
import { none, some } from "fp-ts/lib/Option";

import {
ApiNewMessageWithDefaults,
canDefaultAddresses,
canPaymentAmount,
canWriteMessage,
Expand Down Expand Up @@ -44,6 +43,7 @@ import {
} from "../../__mocks__/mocks";
import { initAppInsights } from "italia-ts-commons/lib/appinsights";
import { mockOrchestratorContext } from "../../__mocks__/durable-functions";
import { ApiNewMessageWithDefaults } from "../types";

//
// tests
Expand Down
93 changes: 93 additions & 0 deletions CreateMessage/__tests__/types.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { WithinRangeString } from "@pagopa/ts-commons/lib/strings";
import * as t from "io-ts";
import { toString } from "fp-ts/lib/function";
import { readableReport } from "italia-ts-commons/lib/reporters";
import { ApiNewMessageWithContentOf } from "../types";
import { PaymentData } from "@pagopa/io-functions-commons/dist/generated/definitions/PaymentData";

const aMessageContent = { subject: "a".repeat(10), markdown: "a".repeat(80) };

describe("ApiNewMessageWithContentOf", () => {
it("should decode a specific subject", () => {
const aSubject = "my specific subject";
const aMessageWithSuchSubject = {
content: { ...aMessageContent, subject: aSubject }
};
const aMessageWithDifferentSubject = {
content: { ...aMessageContent }
};
const pattern = t.interface({
subject: t.intersection([WithinRangeString(10, 121), t.literal(aSubject)])
});

const codec = ApiNewMessageWithContentOf(pattern);

// positive scenario: we expect a match
codec.decode(aMessageWithSuchSubject).fold(
e => fail(`Should have decoded the value: ${readableReport(e)}`),
e => {
expect(e.content.subject).toBe(aSubject);
}
);

// negative scenario: we expect a no-match
codec.decode(aMessageWithDifferentSubject).fold(
_ => {
expect(true).toBe(true);
},
e => fail(`Should have not decoded the value: ${toString(e)}`)
);
});

it("should decode a specific payment data", () => {
const aPaymentData = { amount: 2, notice_number: "011111111111111111" };
const aMessageWithSuchPaymentData = {
content: { ...aMessageContent, payment_data: aPaymentData }
};
const aMessageWithNoPaymentData = {
content: { ...aMessageContent }
};

const aMessageWithAnotherPaymentData = {
content: {
...aMessageContent,
payment_data: { amount: 3, notice_number: "101111111111111111" }
}
};
const pattern = t.interface({
payment_data: t.intersection([
PaymentData,
t.interface({
amount: t.literal(aPaymentData.amount),
notice_number: t.literal(aPaymentData.notice_number)
})
])
});

const codec = ApiNewMessageWithContentOf(pattern);

// positive scenario: we expect a match
codec.decode(aMessageWithSuchPaymentData).fold(
e => fail(`Should have decoded the value: ${readableReport(e)}`),
e => {
expect(e.content.payment_data).toEqual(
expect.objectContaining(aPaymentData)
);
}
);

// negative scenario: we expect a no-match
codec.decode(aMessageWithNoPaymentData).fold(
_ => {
expect(true).toBe(true);
},
e => fail(`Should have not decoded the value: ${toString(e)}`)
);
codec.decode(aMessageWithAnotherPaymentData).fold(
_ => {
expect(true).toBe(true);
},
e => fail(`Should have not decoded the value: ${toString(e)}`)
);
});
});
20 changes: 9 additions & 11 deletions CreateMessage/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import { Context } from "@azure/functions";

import * as express from "express";

import * as df from "durable-functions";

import { Either, isLeft, left, right } from "fp-ts/lib/Either";
Expand All @@ -15,8 +14,8 @@ import { fromEither, TaskEither, tryCatch } from "fp-ts/lib/TaskEither";
import * as t from "io-ts";

import { FiscalCode } from "@pagopa/io-functions-commons/dist/generated/definitions/FiscalCode";
import { EUCovidCert } from "@pagopa/io-functions-commons/dist/generated/definitions/EUCovidCert";
import { NewMessage as ApiNewMessage } from "@pagopa/io-functions-commons/dist/generated/definitions/NewMessage";
import { TimeToLiveSeconds } from "@pagopa/io-functions-commons/dist/generated/definitions/TimeToLiveSeconds";
import { CreatedMessageEvent } from "@pagopa/io-functions-commons/dist/src/models/created_message_event";
import {
Message,
Expand All @@ -28,6 +27,7 @@ import {
ValidService
} from "@pagopa/io-functions-commons/dist/src/models/service";
import {
AzureAllowBodyPayloadMiddleware,
AzureApiAuthMiddleware,
IAzureApiAuthorization,
UserGroup
Expand Down Expand Up @@ -81,14 +81,7 @@ import {
import { NonEmptyString } from "italia-ts-commons/lib/strings";
import { PromiseType } from "italia-ts-commons/lib/types";
import { ServiceId } from "@pagopa/io-functions-commons/dist/generated/definitions/ServiceId";

const ApiNewMessageWithDefaults = t.intersection([
ApiNewMessage,
t.interface({ time_to_live: TimeToLiveSeconds })
]);
export type ApiNewMessageWithDefaults = t.TypeOf<
typeof ApiNewMessageWithDefaults
>;
import { ApiNewMessageWithContentOf, ApiNewMessageWithDefaults } from "./types";

/**
* A request middleware that validates the Message payload.
Expand Down Expand Up @@ -519,7 +512,12 @@ export function CreateMessage(
// extracts the create message payload from the request body
MessagePayloadMiddleware,
// extracts the optional fiscal code from the request params
OptionalFiscalCodeMiddleware
OptionalFiscalCodeMiddleware,
// Ensures only users in ApiMessageWriteEUCovidCert group can send messages with EUCovidCert payload
AzureAllowBodyPayloadMiddleware(
ApiNewMessageWithContentOf(t.interface({ eu_covid_cert: EUCovidCert })),
new Set([UserGroup.ApiMessageWriteEUCovidCert])
)
);
return wrapRequestHandler(
middlewaresWrap(
Expand Down
32 changes: 32 additions & 0 deletions CreateMessage/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as t from "io-ts";
import { TimeToLiveSeconds } from "@pagopa/io-functions-commons/dist/generated/definitions/TimeToLiveSeconds";
import { NewMessage as ApiNewMessage } from "@pagopa/io-functions-commons/dist/generated/definitions/NewMessage";

export type ApiNewMessageWithDefaults = t.TypeOf<
typeof ApiNewMessageWithDefaults
>;
export const ApiNewMessageWithDefaults = t.intersection([
ApiNewMessage,
t.interface({ time_to_live: TimeToLiveSeconds })
]);

/**
* Codec that matches a Message with a specific content pattern
*
* @param contentPattern a coded that matches a content pattern
* @returns a codec that specialize ApiNewMessage
*/
export type ApiNewMessageWithContentOf<
T extends Partial<typeof ApiNewMessage._O["content"]>
> = ApiNewMessage & { readonly content: T };
export const ApiNewMessageWithContentOf = <
T extends Partial<typeof ApiNewMessage._O["content"]>
>(
contentPattern: t.Type<T, Partial<typeof ApiNewMessage._O["content"]>>
): t.Type<ApiNewMessage & { readonly content: T }, typeof ApiNewMessage._O> =>
t.intersection([
ApiNewMessage,
t.interface({
content: contentPattern
})
]);
8 changes: 8 additions & 0 deletions openapi/index.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -948,6 +948,14 @@ definitions:
example: TCNZRO80R13C555Y
required:
- nre
eu_covid_cert:
type: object
description: Paylod with access token to retrieve a EU Covid Certificate
properties:
auth_code:
type: string
required:
- auth_code
due_date:
$ref: '#/definitions/Timestamp'
required:
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@
},
"dependencies": {
"@azure/cosmos": "^3.7.2",
"@pagopa/io-functions-commons": "^20.3.4",
"@pagopa/ts-commons": "^9.4.0",
"@pagopa/io-functions-commons": "^20.5.2",
"@pagopa/ts-commons": "^9.4.1",
"applicationinsights": "^1.7.4",
"azure-storage": "^2.10.3",
"cors": "^2.8.4",
Expand Down
76 changes: 50 additions & 26 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
"@azure/abort-controller" "^1.0.0"
tslib "^2.0.0"

"@azure/core-rest-pipeline@^1.0.0":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.0.3.tgz#ed1a22726214816bc41876b2c538841a7669d98f"
integrity sha512-GbfBQHF83RQI+LVISh8RLKpPeyufFsu6FhwB0U1inN7BWo8GuE23s0vc/D4gd5AWww7orQ20Q3zMzW5FKFs4MQ==
"@azure/core-rest-pipeline@^1.0.3":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@azure/core-rest-pipeline/-/core-rest-pipeline-1.0.4.tgz#f9b55bfa58e0d9d2e4ba9092bed874906d380a28"
integrity sha512-RTB2i7/xMRsrCnDMv7a7zjQknRRI8MxBYoAi9uyKoplFAtT7jKfZaKUpMd0uUQBrbdVt61GO6d1ejYcMXTAQSg==
dependencies:
"@azure/abort-controller" "^1.0.0"
"@azure/core-auth" "^1.3.0"
Expand All @@ -41,13 +41,13 @@
"@opentelemetry/api" "1.0.0-rc.0"
tslib "^2.0.0"

"@azure/cosmos@^3.7.2", "@azure/cosmos@^3.9.0":
version "3.11.0"
resolved "https://registry.yarnpkg.com/@azure/cosmos/-/cosmos-3.11.0.tgz#56a9225b3d40e99bc21c4455a1f1ae4991f424cf"
integrity sha512-E4I1P7qV9PBr6D1Ea5UW/QQ6VS6bbBCmf2y0cWVmR6/0B8IVTsHQEjTzMqTKvu3Cuxgl6/FUsBRw9m684RLBzA==
"@azure/cosmos@^3.11.1", "@azure/cosmos@^3.7.2":
version "3.11.3"
resolved "https://registry.yarnpkg.com/@azure/cosmos/-/cosmos-3.11.3.tgz#422db38bdafaaac50d01dd6a85306f40ef3fb6c2"
integrity sha512-UaY6/87Jf4Pfqi1tEUhwJeaLzhpU0GajB55kU3UXs4bqQK+JPOUJXCe+TJtUD6vRd3RdwmoyoRF8k9cJ6LSQzQ==
dependencies:
"@azure/core-auth" "^1.3.0"
"@azure/core-rest-pipeline" "^1.0.0"
"@azure/core-rest-pipeline" "^1.0.3"
debug "^4.1.1"
fast-json-stable-stringify "^2.0.0"
jsbi "^3.1.3"
Expand Down Expand Up @@ -614,24 +614,24 @@
eslint-plugin-sonarjs "^0.5.0"
prettier "^2.1.2"

"@pagopa/io-functions-commons@^20.3.4":
version "20.3.4"
resolved "https://registry.yarnpkg.com/@pagopa/io-functions-commons/-/io-functions-commons-20.3.4.tgz#4291ad1119f45daa8870ea3f545093d44cb1ea4e"
integrity sha512-UDrUwAC3zE+3Po3iAxsJFqRDtzAitw2xU94bVaTMezZDabLN/nTRQFlPSu3mQjTaRK9Y4igUOHKNGdUM2ALC2Q==
"@pagopa/io-functions-commons@^20.5.2":
version "20.5.2"
resolved "https://registry.yarnpkg.com/@pagopa/io-functions-commons/-/io-functions-commons-20.5.2.tgz#8cce05a52b734e40649c6c9ec7843226319c8d67"
integrity sha512-3L3CML8CmaE6XwPL9+A64Pwpx/UP+6qwlThoWt1eAkCvKyGYSff5Wi8bO+NXTJaaiVr+352PEQ/D5W08WJ1VWg==
dependencies:
"@azure/cosmos" "^3.9.0"
"@pagopa/ts-commons" "^9.4.0"
"@azure/cosmos" "^3.11.1"
"@pagopa/ts-commons" "^9.4.1"
"@types/node-fetch" "^2.5.6"
applicationinsights "^1.8.5"
applicationinsights "^1.8.10"
azure-storage "^2.10.3"
cidr-matcher "^2.1.0"
cidr-matcher "^2.1.1"
fp-ts "1.17.4"
helmet "^4.5.0"
helmet "^4.6.0"
helmet-csp "^2.5.1"
io-functions-express "^0.1.1"
io-functions-express "^1.1.0"
io-ts "1.8.5"
node-fetch "^2.6.1"
nodemailer "^4.6.7"
nodemailer "^6.5.0"
nodemailer-sendgrid "^1.0.3"
referrer-policy "^1.1.0"
rehype-stringify "^3.0.0"
Expand All @@ -640,7 +640,7 @@
remark-rehype "^3.0.0"
request-ip "^2.1.3"
ulid "^2.3.0"
unified "^9.0.0"
unified "^9.2.1"
winston "^3.1.0"

"@pagopa/openapi-codegen-ts@^9.2.0":
Expand All @@ -657,7 +657,7 @@
write-yaml-file "^4.1.3"
yargs "^11.1.0"

"@pagopa/ts-commons@^9.2.0", "@pagopa/ts-commons@^9.4.0":
"@pagopa/ts-commons@^9.2.0":
version "9.4.0"
resolved "https://registry.yarnpkg.com/@pagopa/ts-commons/-/ts-commons-9.4.0.tgz#680ba8a43db4c0397e6c4e8f9cfd3d758cc0b30c"
integrity sha512-eLuyLQPQsQArCHTfcLhtES8dan6GaJ99AfqbyZS8VsyZxuOZ0lyCZkFQBdd9QlmGUHXiEpLVjVEz+uXcGSnLUg==
Expand All @@ -671,6 +671,20 @@
node-fetch "^2.6.0"
validator "^10.1.0"

"@pagopa/ts-commons@^9.4.1":
version "9.4.1"
resolved "https://registry.yarnpkg.com/@pagopa/ts-commons/-/ts-commons-9.4.1.tgz#cc2c1c08c84fb6fa55a99c506227b8c2dcc69c01"
integrity sha512-wA/eInP9l0vPovR4+50vpVxHdUr/el0xUrJ0LoRJv6qAErS9NzGIDwyg4ZjW6SHxDGzN4PpIFSb0QFki27wswg==
dependencies:
abort-controller "^3.0.0"
agentkeepalive "^4.1.2"
applicationinsights "^1.7.4"
fp-ts "1.17.4"
io-ts "1.8.5"
json-set-map "^1.0.2"
node-fetch "^2.6.0"
validator "^10.1.0"

"@sendgrid/client@^6.5.5":
version "6.5.5"
resolved "https://registry.yarnpkg.com/@sendgrid/client/-/client-6.5.5.tgz#66cf569445d98a795998a894bb432a9939ead7c3"
Expand Down Expand Up @@ -1242,7 +1256,7 @@ applicationinsights@^1.7.4:
diagnostic-channel "0.2.0"
diagnostic-channel-publishers "^0.3.3"

applicationinsights@^1.8.5:
applicationinsights@^1.8.10:
version "1.8.10"
resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.8.10.tgz#fffa482cd1519880fb888536a87081ac05130667"
integrity sha512-ZLDA7mShh4mP2Z/HlFolmvhBPX1LfnbIWXrselyYVA7EKjHhri1fZzpu2EiWAmfbRxNBY6fRjoPJWbx5giKy4A==
Expand Down Expand Up @@ -1770,7 +1784,7 @@ ci-info@^2.0.0:
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==

cidr-matcher@^2.1.0:
cidr-matcher@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/cidr-matcher/-/cidr-matcher-2.1.1.tgz#01a489f291bfbc7a3a14358120a6d839a98b1c90"
integrity sha512-QPJRz4HDQxpB8AZWEqd6ejVp+siArXh3u1MYaUFV85cd293StGSMb87jVe0z9gS92KsFwxCxjb3utO3e5HKHTw==
Expand Down Expand Up @@ -3653,7 +3667,7 @@ helmet-csp@^2.5.1:
content-security-policy-builder "2.1.0"
dasherize "2.0.0"

helmet@^4.5.0:
helmet@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/helmet/-/helmet-4.6.0.tgz#579971196ba93c5978eb019e4e8ec0e50076b4df"
integrity sha512-HVqALKZlR95ROkrnesdhbbZJFi/rIVSoNq6f3jA/9u6MIbTsPh3xZwihjeI5+DO/2sOV6HMHooXcEOuwskHpTg==
Expand Down Expand Up @@ -3886,6 +3900,11 @@ io-functions-express@^0.1.1:
resolved "https://registry.yarnpkg.com/io-functions-express/-/io-functions-express-0.1.1.tgz#6ae954fe89ec1d797c5e5d10eca5e77f08ff4a4d"
integrity sha512-Co7sovRyB0lxgU6NFh5v72Apude3XbgKQtqA7slryvKoEqLAvlnLU7DtsYVoF62O3ZJdtSHYf9JWuhDc/di1mg==

io-functions-express@^1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/io-functions-express/-/io-functions-express-1.1.2.tgz#3025242c2096e443a889c7eb8cb7555fb7f1e5c6"
integrity sha512-Gy+g5QQ7k+WnG9TpbgHXObIKrIj05iY/0uK86k+rTyTg6JF9YXVWCnKKmxX2LsJqLpWQtdwOQSwRQhNSfs/rxg==

[email protected]:
version "1.8.5"
resolved "https://registry.yarnpkg.com/io-ts/-/io-ts-1.8.5.tgz#2e102f7f518abe17b0f7e7ede0db54a4c4ddc188"
Expand Down Expand Up @@ -5630,6 +5649,11 @@ nodemailer@^4.6.7:
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-4.7.0.tgz#4420e06abfffd77d0618f184ea49047db84f4ad8"
integrity sha512-IludxDypFpYw4xpzKdMAozBSkzKHmNBvGanUREjJItgJ2NYcK/s8+PggVhj7c2yGFQykKsnnmv1+Aqo0ZfjHmw==

nodemailer@^6.5.0:
version "6.6.1"
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.6.1.tgz#2a05fbf205b897d71bf43884167b5d4d3bd01b99"
integrity sha512-1xzFN3gqv+/qJ6YRyxBxfTYstLNt0FCtZaFRvf4Sg9wxNGWbwFmGXVpfSi6ThGK6aRxAo+KjHtYSW8NvCsNSAg==

normalize-package-data@^2.0.0, normalize-package-data@^2.3.2:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
Expand Down Expand Up @@ -7823,7 +7847,7 @@ unherit@^1.0.4:
inherits "^2.0.0"
xtend "^4.0.0"

unified@^9.0.0:
unified@^9.2.1:
version "9.2.1"
resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.1.tgz#ae18d5674c114021bfdbdf73865ca60f410215a3"
integrity sha512-juWjuI8Z4xFg8pJbnEZ41b5xjGUWGHqXALmBZ3FC3WX0PIx1CZBIIJ6mXbYMcf6Yw4Fi0rFUTA1cdz/BglbOhA==
Expand Down