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

[#IC-303] Add Message View to User Data Extract and Delete #186

Merged
merged 2 commits into from
Apr 29, 2022
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
44 changes: 44 additions & 0 deletions DeleteUserDataActivity/__tests__/backupAndDelete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as TE from "fp-ts/lib/TaskEither";
import { ValidationError } from "io-ts";
import { MessageDeletableModel } from "../../utils/extensions/models/message";
import { MessageStatusDeletableModel } from "../../utils/extensions/models/message_status";
import { MessageViewDeletableModel } from "../../utils/extensions/models/message_view";
import { NotificationDeletableModel } from "../../utils/extensions/models/notification";
import { NotificationStatusDeletableModel } from "../../utils/extensions/models/notification_status";
import { ProfileDeletableModel } from "../../utils/extensions/models/profile";
Expand All @@ -17,6 +18,7 @@ import {
aFiscalCode,
aMessageContent,
aRetrievedMessageStatus,
aRetrievedMessageView,
aRetrievedMessageWithContent,
aRetrievedNotification,
aRetrievedNotificationStatus,
Expand Down Expand Up @@ -59,6 +61,16 @@ const messageModel = ({
deleteMessage: mockDeleteMessage
} as unknown) as MessageDeletableModel;

const mockDeleteMessageView = jest.fn(() => TE.of(true));
const mockFindMessageView = jest.fn<
ReturnType<InstanceType<typeof MessageViewDeletableModel>["find"]>,
Parameters<InstanceType<typeof MessageViewDeletableModel>["find"]>
>(() => TE.of(some(aRetrievedMessageView)));
const messageViewModel = ({
find: mockFindMessageView,
deleteMessageView: mockDeleteMessageView
} as unknown) as MessageViewDeletableModel;

// ServicePreferences Model
const mockDeleteServicePreferences = jest.fn<
ReturnType<InstanceType<typeof ServicePreferencesDeletableModel>["delete"]>,
Expand Down Expand Up @@ -145,6 +157,7 @@ describe(`backupAndDeleteAllUserData`, () => {
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand All @@ -169,6 +182,7 @@ describe(`backupAndDeleteAllUserData`, () => {
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand All @@ -193,6 +207,7 @@ describe(`backupAndDeleteAllUserData`, () => {
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand All @@ -210,6 +225,7 @@ describe(`backupAndDeleteAllUserData`, () => {
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand All @@ -232,6 +248,30 @@ describe(`backupAndDeleteAllUserData`, () => {
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
userDataBackup,
servicePreferencesModel,
fiscalCode: aFiscalCode
})();

expect(E.isRight(result)).toBe(true);
});

it("should stop if there is an error while looking for a message View (404)", async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Add

expect(mockDeleteMessageView).not.toHaveBeenCalled();

mockFindMessageView.mockImplementationOnce(() =>
TE.left({
kind: "COSMOS_ERROR_RESPONSE",
error: { code: 404, name: "", message: "" }
})
);
const result = await backupAndDeleteAllUserData({
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand All @@ -241,6 +281,7 @@ describe(`backupAndDeleteAllUserData`, () => {
})();

expect(E.isRight(result)).toBe(true);
expect(mockDeleteMessageView).not.toHaveBeenCalled();
});

it("should not stop if no servicePreferences were found", async () => {
Expand All @@ -251,6 +292,7 @@ describe(`backupAndDeleteAllUserData`, () => {
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand All @@ -277,6 +319,7 @@ describe(`backupAndDeleteAllUserData`, () => {
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand All @@ -303,6 +346,7 @@ describe(`backupAndDeleteAllUserData`, () => {
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand Down
61 changes: 60 additions & 1 deletion DeleteUserDataActivity/backupAndDelete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import * as TE from "fp-ts/lib/TaskEither";

import { array, flatten, rights } from "fp-ts/lib/Array";
import { MessageContent } from "@pagopa/io-functions-commons/dist/generated/definitions/MessageContent";
import { RetrievedMessageWithoutContent } from "@pagopa/io-functions-commons/dist/src/models/message";
import {
RetrievedMessage,
RetrievedMessageWithoutContent
} from "@pagopa/io-functions-commons/dist/src/models/message";
import { RetrievedMessageStatus } from "@pagopa/io-functions-commons/dist/src/models/message_status";
import { RetrievedNotification } from "@pagopa/io-functions-commons/dist/src/models/notification";
import { RetrievedNotificationStatus } from "@pagopa/io-functions-commons/dist/src/models/notification_status";
Expand All @@ -18,12 +21,14 @@ import { CosmosErrors } from "@pagopa/io-functions-commons/dist/src/utils/cosmos
import { Errors } from "io-ts";
import { RetrievedServicePreference } from "@pagopa/io-functions-commons/dist/src/models/service_preference";
import { flow, pipe } from "fp-ts/lib/function";
import { RetrievedMessageView } from "@pagopa/io-functions-commons/dist/src/models/message_view";
import { MessageDeletableModel } from "../utils/extensions/models/message";
import { MessageStatusDeletableModel } from "../utils/extensions/models/message_status";
import { NotificationDeletableModel } from "../utils/extensions/models/notification";
import { NotificationStatusDeletableModel } from "../utils/extensions/models/notification_status";
import { ProfileDeletableModel } from "../utils/extensions/models/profile";
import { ServicePreferencesDeletableModel } from "../utils/extensions/models/service_preferences";
import { MessageViewDeletableModel } from "../utils/extensions/models/message_view";
import { DataFailure, IBlobServiceInfo, QueryFailure } from "./types";
import { saveDataToBlob } from "./utils";
import { toDocumentDeleteFailure, toQueryFailure } from "./utils";
Expand Down Expand Up @@ -200,6 +205,50 @@ const backupAndDeleteNotificationStatus = ({
notificationStatusModel.findAllVersionsByNotificationId(notification.id)
);

/**
* Backup and delete a given message
*
* @param param0.messageViewModel instance of MessageViewModel
* @param param0.userDataBackup information about the blob storage account to place backup into
* @param param0.message the message
*/
const backupAndDeleteMessageView = ({
messageViewModel,
userDataBackup,
message
}: {
readonly messageViewModel: MessageViewDeletableModel;
readonly userDataBackup: IBlobServiceInfo;
readonly message: RetrievedMessage;
}): TE.TaskEither<DataFailure, O.Option<RetrievedMessageView>> =>
pipe(
messageViewModel.find([message.id, message.fiscalCode]),
TE.chain(TE.fromOption(() => undefined)),
TE.foldW(
_ =>
// unfortunately, a document not found is threated like a query error
TE.of(O.none),
messageView =>
pipe(
saveDataToBlob(
userDataBackup,
`message-view/${message.id}.json`,
messageView
),
TE.chainW(_ =>
pipe(
messageViewModel.deleteMessageView(
message.fiscalCode,
message.id
),
TE.mapLeft(toDocumentDeleteFailure)
)
),
TE.map(_ => O.some(messageView))
)
)
);

/**
* Backup and delete a given message
*
Expand Down Expand Up @@ -378,6 +427,7 @@ const backupAndDeleteAllMessagesData = ({
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
userDataBackup,
Expand All @@ -386,6 +436,7 @@ const backupAndDeleteAllMessagesData = ({
readonly messageContentBlobService: BlobService;
readonly messageModel: MessageDeletableModel;
readonly messageStatusModel: MessageStatusDeletableModel;
readonly messageViewModel: MessageViewDeletableModel;
readonly notificationModel: NotificationDeletableModel;
readonly notificationStatusModel: NotificationStatusDeletableModel;
readonly userDataBackup: IBlobServiceInfo;
Expand All @@ -412,6 +463,11 @@ const backupAndDeleteAllMessagesData = ({
const retrievedMessage = (message as any) as RetrievedMessageWithoutContent;
return pipe(
sequenceT(TE.ApplicativeSeq)(
backupAndDeleteMessageView({
message: retrievedMessage,
messageViewModel,
userDataBackup
}),
backupAndDeleteMessageContent({
message: retrievedMessage,
messageContentBlobService,
Expand Down Expand Up @@ -464,6 +520,7 @@ export const backupAndDeleteAllUserData = ({
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand All @@ -474,6 +531,7 @@ export const backupAndDeleteAllUserData = ({
readonly messageContentBlobService: BlobService;
readonly messageModel: MessageDeletableModel;
readonly messageStatusModel: MessageStatusDeletableModel;
readonly messageViewModel: MessageViewDeletableModel;
readonly notificationModel: NotificationDeletableModel;
readonly notificationStatusModel: NotificationStatusDeletableModel;
readonly profileModel: ProfileDeletableModel;
Expand All @@ -487,6 +545,7 @@ export const backupAndDeleteAllUserData = ({
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
userDataBackup
Expand Down
4 changes: 4 additions & 0 deletions DeleteUserDataActivity/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { NotificationDeletableModel } from "../utils/extensions/models/notificat
import { NotificationStatusDeletableModel } from "../utils/extensions/models/notification_status";
import { ProfileDeletableModel } from "../utils/extensions/models/profile";
import { ServicePreferencesDeletableModel } from "../utils/extensions/models/service_preferences";
import { MessageViewDeletableModel } from "../utils/extensions/models/message_view";
import { backupAndDeleteAllUserData } from "./backupAndDelete";
import {
ActivityInput,
Expand All @@ -31,6 +32,7 @@ const logPrefix = `DeleteUserDataActivity`;
export interface IActivityHandlerInput {
readonly messageModel: MessageDeletableModel;
readonly messageStatusModel: MessageStatusDeletableModel;
readonly messageViewModel: MessageViewDeletableModel;
readonly notificationModel: NotificationDeletableModel;
readonly notificationStatusModel: NotificationStatusDeletableModel;
readonly profileModel: ProfileDeletableModel;
Expand All @@ -48,6 +50,7 @@ export function createDeleteUserDataActivityHandler({
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand Down Expand Up @@ -80,6 +83,7 @@ export function createDeleteUserDataActivityHandler({
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand Down
9 changes: 9 additions & 0 deletions DeleteUserDataActivity/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createBlobService } from "azure-storage";
import { MESSAGE_COLLECTION_NAME } from "@pagopa/io-functions-commons/dist/src/models/message";
import { MESSAGE_STATUS_COLLECTION_NAME } from "@pagopa/io-functions-commons/dist/src/models/message_status";
import { MESSAGE_VIEW_COLLECTION_NAME } from "@pagopa/io-functions-commons/dist/src/models/message_view";
import { NOTIFICATION_COLLECTION_NAME } from "@pagopa/io-functions-commons/dist/src/models/notification";
import { NOTIFICATION_STATUS_COLLECTION_NAME } from "@pagopa/io-functions-commons/dist/src/models/notification_status";
import { PROFILE_COLLECTION_NAME } from "@pagopa/io-functions-commons/dist/src/models/profile";
Expand All @@ -13,6 +14,7 @@ import { NotificationDeletableModel } from "../utils/extensions/models/notificat
import { NotificationStatusDeletableModel } from "../utils/extensions/models/notification_status";
import { ProfileDeletableModel } from "../utils/extensions/models/profile";
import { ServicePreferencesDeletableModel } from "../utils/extensions/models/service_preferences";
import { MessageViewDeletableModel } from "../utils/extensions/models/message_view";
import { createDeleteUserDataActivityHandler } from "./handler";

const config = getConfigOrThrow();
Expand All @@ -34,6 +36,12 @@ const messageStatusModel = new MessageStatusDeletableModel(
messageStatusesContainer
);

const messageViewContainer = cosmosdbClient
.database(config.COSMOSDB_NAME)
.container(MESSAGE_VIEW_COLLECTION_NAME);

const messageViewModel = new MessageViewDeletableModel(messageViewContainer);

const notificationsContainer = cosmosdbClient
.database(config.COSMOSDB_NAME)
.container(NOTIFICATION_COLLECTION_NAME);
Expand Down Expand Up @@ -75,6 +83,7 @@ const activityFunctionHandler = createDeleteUserDataActivityHandler({
messageContentBlobService,
messageModel,
messageStatusModel,
messageViewModel,
notificationModel,
notificationStatusModel,
profileModel,
Expand Down
15 changes: 15 additions & 0 deletions ExtractUserDataActivity/__tests__/handler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as zipstream from "../../utils/zip";
import { context as contextMock } from "../../__mocks__/durable-functions";
import {
aFiscalCode,
aMessageView,
aProfile,
aRetrievedMessageStatus,
aRetrievedNotificationStatus
Expand Down Expand Up @@ -43,6 +44,7 @@ import {
import { AllUserData } from "../../utils/userData";
import { none } from "fp-ts/lib/Option";
import { pipe } from "fp-ts/lib/function";
import { MessageViewModel } from "@pagopa/io-functions-commons/dist/src/models/message_view";

const anotherRetrievedNotification: RetrievedNotification = {
...aRetrievedNotification,
Expand Down Expand Up @@ -108,6 +110,14 @@ const messageModelMock = ({
getContentFromBlob: mockGetContentFromBlob
} as any) as MessageModel;

const iteratorGenMock = async function*(arr: any[]) {
for (let a of arr) yield a;
};

const messageViewModelMock = ({
getQueryIterator: jest.fn(() => iteratorGenMock([E.right(aMessageView)]))
} as any) as MessageViewModel;

const messageStatusModelMock = ({
findLastVersionByModelId: jest.fn(() =>
TE.fromEither(E.right(some(aRetrievedMessageStatus)))
Expand Down Expand Up @@ -172,6 +182,7 @@ describe("createExtractUserDataActivityHandler", () => {
messageContentBlobService: blobServiceMock,
messageModel: messageModelMock,
messageStatusModel: messageStatusModelMock,
messageViewModel: messageViewModelMock,
notificationModel: notificationModelMock,
notificationStatusModel: notificationStatusModelMock,
profileModel: profileModelMock,
Expand Down Expand Up @@ -209,6 +220,7 @@ describe("createExtractUserDataActivityHandler", () => {
messageContentBlobService: blobServiceMock,
messageModel: messageModelMock,
messageStatusModel: messageStatusModelMock,
messageViewModel: messageViewModelMock,
notificationModel: notificationWebhookModelMock,
notificationStatusModel: notificationStatusModelMock,
profileModel: profileModelMock,
Expand Down Expand Up @@ -238,6 +250,7 @@ describe("createExtractUserDataActivityHandler", () => {
messageContentBlobService: blobServiceMock,
messageModel: messageModelMock,
messageStatusModel: messageStatusModelMock,
messageViewModel: messageViewModelMock,
notificationModel: notificationModelMock,
notificationStatusModel: notificationStatusModelMock,
profileModel: profileModelMock,
Expand Down Expand Up @@ -281,6 +294,7 @@ describe("createExtractUserDataActivityHandler", () => {
messageContentBlobService: blobServiceMock,
messageModel: messageModelMock,
messageStatusModel: messageStatusModelMock,
messageViewModel: messageViewModelMock,
notificationModel: notificationModelMock,
notificationStatusModel: notificationStatusModelMock,
profileModel: profileModelMock,
Expand All @@ -303,6 +317,7 @@ describe("createExtractUserDataActivityHandler", () => {
messageContentBlobService: blobServiceMock,
messageModel: messageModelMock,
messageStatusModel: messageStatusModelMock,
messageViewModel: messageViewModelMock,
notificationModel: notificationModelMock,
notificationStatusModel: notificationStatusModelMock,
profileModel: profileModelMock,
Expand Down
Loading