Skip to content

Commit

Permalink
feat: added getWalletInstanceStatus and setWalletInstanceStatus endpoint
Browse files Browse the repository at this point in the history
Refs: #1171 SIW-1775
  • Loading branch information
silvicir authored Nov 19, 2024
1 parent 003412f commit 3cbd2ad
Show file tree
Hide file tree
Showing 6 changed files with 336 additions and 77 deletions.
58 changes: 50 additions & 8 deletions api_io_wallet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -83,39 +83,70 @@ paths:
$ref: "#/components/responses/ServiceUnavailable"

/wallet-instances/current/status:
put:
summary: Revoke current Wallet Instance
operationId: setCurrentWalletInstanceStatus
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/SetWalletInstanceStatusBody"
responses:
"204":
description: Wallet Instance status successfully set
"400":
$ref: "#/components/responses/BadRequest"
"403":
$ref: "#/components/responses/Forbidden"
"422":
$ref: "#/components/responses/UnprocessableContent"
"500":
$ref: "#/components/responses/Unexpected"
"503":
$ref: "#/components/responses/ServiceUnavailable"

/wallet-instances/{id}/status:
parameters:
- in: path
name: id
required: true
schema:
type: string
get:
summary: Retrieve the current Wallet Instance status
operationId: getCurrentWalletInstanceStatus
summary: Retrieve a Wallet Instance status
operationId: getWalletInstanceStatus
responses:
"200":
description: Wallet Instance status successfully retrieved
content:
application/json:
schema:
$ref: "#/components/schemas/WalletInstanceData"
"400":
$ref: "#/components/responses/BadRequest"
"403":
$ref: "#/components/responses/Forbidden"
"404":
$ref: "#/components/responses/NotFound"
"500":
$ref: "#/components/responses/Unexpected"
"503":
$ref: "#/components/responses/ServiceUnavailable"
put:
summary: Revoke current Wallet Instance
operationId: setCurrentWalletInstanceStatus
summary: Revoke a Wallet Instance
operationId: setWalletInstanceStatus
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/SetCurrentWalletInstanceStatusBody"
$ref: "#/components/schemas/SetWalletInstanceStatusBody"
responses:
"204":
description: Wallet Instance status successfully set
"400":
$ref: "#/components/responses/BadRequest"
"403":
$ref: "#/components/responses/Forbidden"
"422":
$ref: "#/components/responses/UnprocessableContent"
"500":
$ref: "#/components/responses/Unexpected"
"503":
Expand Down Expand Up @@ -231,7 +262,7 @@ components:
- grant_type
- assertion

SetCurrentWalletInstanceStatusBody:
SetWalletInstanceStatusBody:
type: object
properties:
status:
Expand All @@ -249,9 +280,20 @@ components:
type: string
is_revoked:
type: boolean
revocation_reason:
$ref: "#/components/schemas/RevocationReason"
required:
- id
- is_revoked

RevocationReason:
type: string
enum:
[
"CERTIFICATE_REVOKED_BY_ISSUER",
"NEW_WALLET_INSTANCE_CREATED",
"REVOKED_BY_USER",
]

ProblemDetail:
type: object
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"generate:proxy:api-session": "rimraf generated/session && gen-api-models --api-spec api_session.yaml --out-dir generated/session",
"generate:lollipop-definitions": "rimraf generated/lollipop && gen-api-models --api-spec openapi/lollipop_definitions.yaml --out-dir generated/lollipop",
"generate:lollipop-first-sign": "rimraf generated/lollipop-first-consumer && gen-api-models --api-spec openapi/consumed/lollipop_first_consumer.yaml --out-dir generated/lollipop-first-consumer --request-types --response-decoders --client",
"generate:api:io-wallet": "rimraf generated/io-wallet-api && gen-api-models --api-spec https://raw.githubusercontent.com/pagopa/io-wallet/io-wallet-user-func@2.0.0/apps/io-wallet-user-func/openapi.yaml --no-strict --out-dir generated/io-wallet-api --request-types --response-decoders --client",
"generate:api:io-wallet": "rimraf generated/io-wallet-api && gen-api-models --api-spec https://raw.githubusercontent.com/pagopa/io-wallet/io-wallet-user-func@2.0.1/apps/io-wallet-user-func/openapi.yaml --no-strict --out-dir generated/io-wallet-api --request-types --response-decoders --client",
"generate:proxy:io-wallet-models": "rimraf generated/io-wallet && gen-api-models --api-spec api_io_wallet.yaml --out-dir generated/io-wallet",
"postversion": "git push && git push --tags",
"dist:modules": "modclean -r -n default:safe && yarn install --production",
Expand Down
14 changes: 12 additions & 2 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1467,6 +1467,7 @@ function registerIoWalletAPIRoutes(
)
);

// TODO SIW-1843
app.put(
`${basePath}/wallet-instances/current/status`,
bearerSessionTokenAuth,
Expand All @@ -1477,10 +1478,19 @@ function registerIoWalletAPIRoutes(
);

app.get(
`${basePath}/wallet-instances/current/status`,
`${basePath}/wallet-instances/:walletInstanceId/status`,
bearerSessionTokenAuth,
toExpressHandler(
ioWalletController.getWalletInstanceStatus,
ioWalletController
)
);

app.put(
`${basePath}/wallet-instances/:walletInstanceId/status`,
bearerSessionTokenAuth,
toExpressHandler(
ioWalletController.getCurrentWalletInstanceStatus,
ioWalletController.setWalletInstanceStatus,
ioWalletController
)
);
Expand Down
110 changes: 81 additions & 29 deletions src/controllers/ioWalletController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from "@pagopa/ts-commons/lib/responses";

import { pipe } from "fp-ts/lib/function";
import { sequenceS } from "fp-ts/lib/Apply";
import { Errors } from "io-ts";
import { FiscalCode, NonEmptyString } from "@pagopa/ts-commons/lib/strings";
import { readableReport } from "@pagopa/ts-commons/lib/reporters";
Expand All @@ -32,7 +33,7 @@ import { CreateWalletInstanceBody } from "../../generated/io-wallet/CreateWallet
import { CreateWalletAttestationBody } from "../../generated/io-wallet/CreateWalletAttestationBody";
import { WalletAttestationView } from "../../generated/io-wallet/WalletAttestationView";
import { FF_IO_WALLET_TRIAL_ENABLED } from "../config";
import { SetCurrentWalletInstanceStatusBody } from "../../generated/io-wallet/SetCurrentWalletInstanceStatusBody";
import { SetWalletInstanceStatusBody } from "../../generated/io-wallet/SetWalletInstanceStatusBody";
import { WalletInstanceData } from "../../generated/io-wallet/WalletInstanceData";

const toValidationError = (errors: Errors) =>
Expand Down Expand Up @@ -125,6 +126,48 @@ export default class IoWalletController {
)()
);

/**
* Update current Wallet Instance status.
*/
public readonly setWalletInstanceStatus = (
req: express.Request
): Promise<
| IResponseErrorInternal
| IResponseSuccessNoContent
| IResponseErrorServiceUnavailable
| IResponseErrorValidation
| IResponseErrorForbiddenNotAuthorized
> =>
withUserFromRequest(req, async (user) =>
pipe(
this.ensureFiscalCodeIsAllowed(user.fiscal_code),
TE.chainW(() =>
pipe(
sequenceS(E.Apply)({
body: pipe(
req.body,
SetWalletInstanceStatusBody.decode,
E.mapLeft(toValidationError)
),
id: pipe(
NonEmptyString.decode(req.params.walletInstanceId),
E.mapLeft(toValidationError)
),
}),
TE.fromEither
)
),
TE.map(({ id, body: { status } }) =>
this.ioWalletService.setWalletInstanceStatus(
id,
status,
user.fiscal_code
)
),
TE.toUnion
)()
);

/**
* Update current Wallet Instance status.
*/
Expand All @@ -144,7 +187,7 @@ export default class IoWalletController {
TE.chainW(() =>
pipe(
req.body,
SetCurrentWalletInstanceStatusBody.decode,
SetWalletInstanceStatusBody.decode,
E.mapLeft(toValidationError),
TE.fromEither
)
Expand All @@ -162,22 +205,31 @@ export default class IoWalletController {
/**
* Get current Wallet Instance status.
*/
public readonly getCurrentWalletInstanceStatus = (
public readonly getWalletInstanceStatus = (
req: express.Request
): Promise<
| IResponseErrorInternal
| IResponseSuccessJson<WalletInstanceData>
| IResponseErrorNotFound
| IResponseErrorInternal
| IResponseErrorServiceUnavailable
| IResponseErrorValidation
| IResponseErrorForbiddenNotAuthorized
> =>
withUserFromRequest(req, async (user) =>
pipe(
this.ensureFiscalCodeIsAllowed(user.fiscal_code),
TE.map(() =>
this.ioWalletService.getCurrentWalletInstanceStatus(user.fiscal_code)
TE.chainW(() =>
pipe(
NonEmptyString.decode(req.params.walletInstanceId),
E.mapLeft(toValidationError),
TE.fromEither
)
),
TE.map((walletInstanceId) =>
this.ioWalletService.getWalletInstanceStatus(
walletInstanceId,
user.fiscal_code
)
),
TE.toUnion
)()
Expand All @@ -186,32 +238,32 @@ export default class IoWalletController {
private readonly ensureUserIsAllowed = (
userId: NonEmptyString
): TE.TaskEither<Error, void> =>
pipe(
TE.tryCatch(
() => this.ioWalletService.getSubscription(userId),
E.toError
),
// if a successful response with state != "ACTIVE" or an error is returned, return left
TE.chain((response) =>
response.kind === "IResponseSuccessJson" &&
response.value.state === "ACTIVE"
? TE.right(undefined)
: TE.left(new Error())
)
);

private readonly ensureFiscalCodeIsAllowed = (fiscalCode: FiscalCode) =>
FF_IO_WALLET_TRIAL_ENABLED
? pipe(
TE.tryCatch(
() => this.ioWalletService.getSubscription(userId),
E.toError
),
// if a successful response with state != "ACTIVE" or an error is returned, return left
TE.chain((response) =>
response.kind === "IResponseSuccessJson" &&
response.value.state === "ACTIVE"
? TE.right(undefined)
: TE.left(new Error())
fiscalCode,
NonEmptyString.decode,
TE.fromEither,
TE.chainW(this.ensureUserIsAllowed),
TE.mapLeft(() =>
getResponseErrorForbiddenNotAuthorized(
"Not authorized to perform this action"
)
)
)
: TE.right(undefined);

private readonly ensureFiscalCodeIsAllowed = (fiscalCode: FiscalCode) =>
pipe(
fiscalCode,
NonEmptyString.decode,
TE.fromEither,
TE.chainW(this.ensureUserIsAllowed),
TE.mapLeft(() =>
getResponseErrorForbiddenNotAuthorized(
"Not authorized to perform this action"
)
)
);
}
Loading

0 comments on commit 3cbd2ad

Please sign in to comment.