Skip to content

Commit

Permalink
Merge branch 'master' into SIW-1794-add-edc-info-box-in-details-screen
Browse files Browse the repository at this point in the history
  • Loading branch information
mastro993 authored Nov 4, 2024
2 parents d5d2b13 + 344b571 commit 1a2e61a
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 19 deletions.
23 changes: 15 additions & 8 deletions ts/features/itwallet/common/saga/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,40 @@ import {
trialSystemActivationStatusUpsert
} from "../../../../trialSystem/store/actions";
import { SubscriptionStateEnum } from "../../../../../../definitions/trial_system/SubscriptionState";
import { trialStatusSelector } from "../../../../trialSystem/store/reducers";
import {
trialStatusPotSelector,
trialStatusSelector
} from "../../../../trialSystem/store/reducers";
import { TrialId } from "../../../../../../definitions/trial_system/TrialId";
import { TrialSystemError } from "../../../../trialSystem/utils/error";

describe("handleTrialSystemSubscription", () => {
it("should handle trial system subscription correctly", async () => {
it("should handle trial system subscription correctly when the endpoint returns 404", async () => {
const trialId = "baz" as TrialId;
const state = SubscriptionStateEnum.UNSUBSCRIBED;
const error = new TrialSystemError(
"User not found",
"TRIAL_SYSTEM_USER_NOT_FOUND"
);
const state = pot.noneError(error);
const store: DeepPartial<GlobalState> = {
trialSystem: {
[trialId]: pot.some(state)
[trialId]: state
}
};
return expectSaga(handleTrialSystemSubscription)
.withState(store)
.put(trialSystemActivationStatus.request(trialId))
.dispatch(
trialSystemActivationStatus.success({
trialSystemActivationStatus.failure({
trialId,
state,
createdAt: new Date()
error
})
)
.take([
trialSystemActivationStatus.success,
trialSystemActivationStatus.failure
])
.provide([[matchers.select(trialStatusSelector), state]])
.provide([[matchers.select(trialStatusPotSelector), state]])
.put(trialSystemActivationStatusUpsert.request(trialId))
.run();
});
Expand Down
16 changes: 11 additions & 5 deletions ts/features/itwallet/common/saga/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { SagaIterator } from "redux-saga";
import { fork, put, call, take, select } from "typed-redux-saga/macro";
import * as pot from "@pagopa/ts-commons/lib/pot";
import { isActionOf } from "typesafe-actions";
import {
trialSystemActivationStatus,
Expand All @@ -13,8 +14,7 @@ import { itwCieIsSupported } from "../../identification/store/actions";
import { watchItwCredentialsSaga } from "../../credentials/saga";
import { watchItwLifecycleSaga } from "../../lifecycle/saga";
import { checkCredentialsStatusAttestation } from "../../credentials/saga/checkCredentialsStatusAttestation";
import { trialStatusSelector } from "../../../trialSystem/store/reducers";
import { SubscriptionStateEnum } from "../../../../../definitions/trial_system/SubscriptionState";
import { trialStatusPotSelector } from "../../../trialSystem/store/reducers";

function* checkWalletInstanceAndCredentialsValiditySaga() {
// Status attestations of credentials are checked only in case of a valid wallet instance.
Expand All @@ -34,9 +34,15 @@ export function* handleTrialSystemSubscription() {
trialSystemActivationStatus.success,
trialSystemActivationStatus.failure
]);
if (isActionOf(trialSystemActivationStatus.success, outputAction)) {
const status = yield* select(trialStatusSelector(itwTrialId));
if (status && status === SubscriptionStateEnum.UNSUBSCRIBED) {
if (isActionOf(trialSystemActivationStatus.failure, outputAction)) {
/* We check if the error is due to the user not being found in the trial system and we try to subscribe the user
the trial system returns 404 if the usuer is not found or if the trial id is not found. However, the trial id is
hardcoded in the config file and we assume it is correct so the only reason for the 404 is the user not being found. */
const potStatus = yield* select(trialStatusPotSelector(itwTrialId));
if (
pot.isError(potStatus) &&
potStatus.error.type === "TRIAL_SYSTEM_USER_NOT_FOUND"
) {
yield* put(trialSystemActivationStatusUpsert.request(itwTrialId));
}
}
Expand Down
3 changes: 2 additions & 1 deletion ts/features/trialSystem/store/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import {
} from "typesafe-actions";
import { TrialId } from "../../../../../definitions/trial_system/TrialId";
import { Subscription } from "../../../../../definitions/trial_system/Subscription";
import { TrialSystemError } from "../../utils/error";

type ErrorPayload = {
trialId: TrialId;
error: Error;
error: TrialSystemError;
};

export const trialSystemActivationStatusUpsert = createAsyncAction(
Expand Down
15 changes: 14 additions & 1 deletion ts/features/trialSystem/store/reducers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import {
} from "../actions";
import { GlobalState } from "../../../../store/reducers/types";
import { itwTrialId } from "../../../../config";
import { TrialSystemError } from "../../utils/error";

export type TrialSystemState = Record<
TrialId,
pot.Pot<SubscriptionState, Error>
pot.Pot<SubscriptionState, TrialSystemError>
>;

const initialState: TrialSystemState = {};
Expand Down Expand Up @@ -109,6 +110,18 @@ export const isUpdatingTrialStatusSelector =
pot.isUpdating
);

/**
* Returns the pot state of a given trial
* @param id - The trial id
* @returns the pot state of the trial
*/
export const trialStatusPotSelector = (id: TrialId) => (state: GlobalState) =>
pipe(
state,
trialSystemActivationStatusSelector,
status => status[id] ?? pot.none
);

/**
* Allows to know if the user has the access to the specified trial
*/
Expand Down
23 changes: 19 additions & 4 deletions ts/features/trialSystem/store/sagas/watchTrialSystemSaga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import { TrialSystemClient, createTrialSystemClient } from "../../api/client";
import { apiUrlPrefix } from "../../../../config";
import {
trialSystemActivationStatus,
trialSystemActivationStatusReset,
trialSystemActivationStatusUpsert
} from "../actions";
import { getError } from "../../../../utils/errors";
import { TrialSystemError } from "../../utils/error";

function* handleTrialSystemActivationStatusUpsert(
upsertTrialSystemActivationStatus: TrialSystemClient["createSubscription"],
Expand Down Expand Up @@ -74,21 +74,36 @@ function* handleTrialSystemActivationStatus(
}

if (result.right.status === 404) {
yield* put(trialSystemActivationStatusReset(action.payload));
/**
* 404 is returned when the user is not found in the trial system. However, the API also returns 404 when the trial id is not found.
* We assume the trial id is correct so the only reason for the 404 is the user not being found.
*/
yield* put(
trialSystemActivationStatus.failure({
trialId: action.payload,
error: new TrialSystemError(
"User not found",
"TRIAL_SYSTEM_USER_NOT_FOUND"
)
})
);
return;
} else {
yield* put(
trialSystemActivationStatus.failure({
trialId: action.payload,
error: new Error(`response status ${result.right.status}`)
error: new TrialSystemError(`response status ${result.right.status}`)
})
);
}
} catch (e) {
yield* put(
trialSystemActivationStatus.failure({
trialId: action.payload,
error: getError(e)
error: new TrialSystemError(
getError(e).message,
"TRIAL_SYSTEM_NETWORK_ERROR"
)
})
);
}
Expand Down
35 changes: 35 additions & 0 deletions ts/features/trialSystem/utils/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
type TrialSystemErrorType =
/* The user is not found in the trial system which corresponds to a 404 error
However, the API also returns 404 when the trial id is not found
We assume the trial id is correct so the only reason for the 404 is the user not being found. */
| "TRIAL_SYSTEM_USER_NOT_FOUND"
| "TRIAL_SYSTEM_GENERIC_ERROR"
| "TRIAL_SYSTEM_NETWORK_ERROR";

/**
* Custom error class for Trial System errors. It allows to specify a type of error
* as some specific errors need to be handled differently.
*/
export class TrialSystemError extends Error {
public readonly type?: TrialSystemErrorType;

constructor(
message: string | undefined,
type: TrialSystemErrorType = "TRIAL_SYSTEM_GENERIC_ERROR"
) {
// Pass parent constructor parameters
super(message);

// Maintains stack trace for where our error was thrown (only available on V8)
if (Error.captureStackTrace) {
Error.captureStackTrace(this, TrialSystemError);
}

this.name = "TrialSystemError";
if (message) {
this.message = message;
}
// Set custom information
this.type = type;
}
}

0 comments on commit 1a2e61a

Please sign in to comment.