From 4759ceae7014771a8a23df4800b0fbd016870621 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 5 Apr 2024 13:01:45 -0300 Subject: wip #8276 --- .../paths/instance/accounts/create/CreatePage.tsx | 69 ++++---- .../src/paths/instance/accounts/create/index.tsx | 173 ++++++++++++++++++++- .../src/paths/instance/accounts/update/index.tsx | 62 +++++++- 3 files changed, 268 insertions(+), 36 deletions(-) (limited to 'packages/merchant-backoffice-ui/src/paths/instance') diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/CreatePage.tsx index dd77d609c..255caa375 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/CreatePage.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/CreatePage.tsx @@ -44,8 +44,8 @@ const accountAuthType = ["none", "basic"]; function isValidURL(s: string): boolean { try { - const u = new URL("/", s) - return true; + const parsed = new URL("/", s); + return parsed instanceof URL; } catch (e) { return false; } @@ -61,43 +61,54 @@ export function CreatePage({ onCreate, onBack }: Props): VNode { credit_facade_credentials: !state.credit_facade_credentials ? undefined : undefinedIfEmpty({ - username: - state.credit_facade_credentials.type === "basic" && !state.credit_facade_credentials.username - ? i18n.str`required` - : undefined, - password: - state.credit_facade_credentials.type === "basic" && !state.credit_facade_credentials.password - ? i18n.str`required` - : undefined, - }), + username: + state.credit_facade_credentials.type === "basic" && + !state.credit_facade_credentials.username + ? i18n.str`required` + : undefined, + password: + state.credit_facade_credentials.type === "basic" && + !state.credit_facade_credentials.password + ? i18n.str`required` + : undefined, + }), credit_facade_url: !state.credit_facade_url ? undefined - : !isValidURL(state.credit_facade_url) ? i18n.str`not valid url` + : !isValidURL(state.credit_facade_url) + ? i18n.str`not valid url` + : undefined, + repeatPassword: !state.credit_facade_credentials + ? undefined + : state.credit_facade_credentials.type === "basic" && + (!state.credit_facade_credentials.password || + state.credit_facade_credentials.password !== state.repeatPassword) + ? i18n.str`is not the same` : undefined, - repeatPassword: - !state.credit_facade_credentials - ? undefined - : state.credit_facade_credentials.type === "basic" && (!state.credit_facade_credentials.password || state.credit_facade_credentials.password !== state.repeatPassword) - ? i18n.str`is not the same` - : undefined, }; const hasErrors = Object.keys(errors).some( - (k) => (errors as any)[k] !== undefined, + (k) => (errors as Record)[k] !== undefined, ); const submitForm = () => { if (hasErrors) return Promise.reject(); - const credit_facade_url = !state.credit_facade_url ? undefined : new URL("/", state.credit_facade_url).href - const credit_facade_credentials: TalerMerchantApi.FacadeCredentials | undefined = - credit_facade_url == undefined ? undefined : - state.credit_facade_credentials?.type === "basic" ? { - type: "basic", - password: state.credit_facade_credentials.password, - username: state.credit_facade_credentials.username, - } : { - type: "none" - } + const credit_facade_url = !state.credit_facade_url + ? undefined + : new URL("/", state.credit_facade_url).href; + const credit_facade_credentials: + | TalerMerchantApi.FacadeCredentials + | undefined = + credit_facade_url == undefined + ? undefined + : state.credit_facade_credentials?.type === "basic" + ? { + type: "basic", + password: state.credit_facade_credentials.password, + username: state.credit_facade_credentials.username, + } + : { + type: "none", + }; return onCreate({ payto_uri: state.payto_uri!, diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx index 3d27b9a1a..96ca8bf5e 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/create/index.tsx @@ -19,8 +19,22 @@ * @author Sebastian Javier Marchano (sebasjm) */ -import { TalerMerchantApi } from "@gnu-taler/taler-util"; -import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { + FacadeCredentials, + HttpStatusCode, + OperationFail, + OperationOk, + TalerError, + TalerMerchantApi, + TalerRevenueHttpClient, + assertUnreachable, + opFixedSuccess, +} from "@gnu-taler/taler-util"; +import { + BrowserFetchHttpLib, + useMerchantApiContext, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { NotificationCard } from "../../../../components/menu/index.js"; @@ -45,10 +59,69 @@ export default function CreateValidator({ onConfirm, onBack }: Props): VNode { { - return api.instance.addBankAccount(state.token, request) + onCreate={async (request: Entity) => { + const revenueAPI = !request.credit_facade_url + ? undefined + : new URL("/", request.credit_facade_url); + + if (revenueAPI) { + const resp = await testRevenueAPI( + revenueAPI, + request.credit_facade_credentials, + ); + if (resp.type === "fail") { + switch (resp.case) { + case "no-config": { + setNotif({ + message: i18n.str`Could not create account`, + type: "ERROR", + description: i18n.str`The endpoint doesn't seems to be a Taler Revenue API`, + }); + return; + } + case "client-bad-request": { + setNotif({ + message: i18n.str`Could not create account`, + type: "ERROR", + description: i18n.str`Server replied with "bad request".`, + }); + return; + } + case "unauthorized": { + setNotif({ + message: i18n.str`Could not create account`, + type: "ERROR", + description: i18n.str`Unauthorized, try with another credentials.`, + }); + return; + } + case "not-found": { + setNotif({ + message: i18n.str`Could not create account`, + type: "ERROR", + description: i18n.str`Check facade URL, server replied with "not found".`, + }); + return; + } + case "error": { + setNotif({ + message: i18n.str`Could not create account`, + type: "ERROR", + description: resp.detail.hint, + }); + return; + } + default: { + assertUnreachable(resp) + } + } + } + } + + return api.instance + .addBankAccount(state.token, request) .then(() => { - onConfirm() + onConfirm(); }) .catch((error) => { setNotif({ @@ -62,3 +135,93 @@ export default function CreateValidator({ onConfirm, onBack }: Props): VNode { ); } + +export async function testRevenueAPI( + revenueAPI: URL, + creds: FacadeCredentials | undefined, +): Promise< + | OperationOk + | OperationFail<"no-config"> + | OperationFail<"client-bad-request"> + | OperationFail<"unauthorized"> + | OperationFail<"not-found"> + | OperationFail<"error"> +> { + const api = new TalerRevenueHttpClient( + revenueAPI.href, + new BrowserFetchHttpLib(), + ); + try { + const config = await api.getConfig(); + if (config.type === "fail") { + return { + type: "fail", + case: "no-config", + detail: { + code: 1, + }, + }; + } + } catch (err) { + if (err instanceof TalerError) { + return { + type: "fail", + case: "error", + detail: err.errorDetail, + }; + } + } + if (creds) { + const auth = + creds.type === "basic" + ? { + username: creds.username, + password: creds.password, + } + : undefined; + + try { + const history = await api.getHistory(auth); + if (history.type === "fail") { + switch (history.case) { + case HttpStatusCode.BadRequest: { + return { + type: "fail", + case: "client-bad-request", + detail: { + code: 1, + }, + }; + } + case HttpStatusCode.Unauthorized: { + return { + type: "fail", + case: "unauthorized", + detail: { + code: 1, + }, + }; + } + case HttpStatusCode.NotFound: { + return { + type: "fail", + case: "not-found", + detail: { + code: 1, + }, + }; + } + } + } + } catch (err) { + if (err instanceof TalerError) { + return { + type: "fail", + case: "error", + detail: err.errorDetail, + }; + } + } + } + return opFixedSuccess(undefined); +} diff --git a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx index 6b8af50a9..cf1d5b0c7 100644 --- a/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx +++ b/packages/merchant-backoffice-ui/src/paths/instance/accounts/update/index.tsx @@ -35,6 +35,7 @@ import { Notification } from "../../../../utils/types.js"; import { LoginPage } from "../../../login/index.js"; import { NotFoundPageOrAdminCreate } from "../../../notfound/index.js"; import { UpdatePage } from "./UpdatePage.js"; +import { testRevenueAPI } from "../create/index.js"; export type Entity = TalerMerchantApi.AccountPatchDetails & WithId; @@ -79,8 +80,65 @@ export default function UpdateValidator({ { - return api.instance.updateBankAccount(state.token, bid, data) + onUpdate={async (request) => { + const revenueAPI = !request.credit_facade_url + ? undefined + : new URL("/", request.credit_facade_url); + + if (revenueAPI) { + const resp = await testRevenueAPI( + revenueAPI, + request.credit_facade_credentials, + ); + if (resp.type === "fail") { + switch (resp.case) { + case "no-config": { + setNotif({ + message: i18n.str`Could not create account`, + type: "ERROR", + description: i18n.str`The endpoint doesn't seems to be a Taler Revenue API`, + }); + return; + } + case "client-bad-request": { + setNotif({ + message: i18n.str`Could not create account`, + type: "ERROR", + description: i18n.str`Server replied with "bad request".`, + }); + return; + } + case "unauthorized": { + setNotif({ + message: i18n.str`Could not create account`, + type: "ERROR", + description: i18n.str`Unauthorized, try with another credentials.`, + }); + return; + } + case "not-found": { + setNotif({ + message: i18n.str`Could not create account`, + type: "ERROR", + description: i18n.str`Check facade URL, server replied with "not found".`, + }); + return; + } + case "error": { + setNotif({ + message: i18n.str`Could not create account`, + type: "ERROR", + description: resp.detail.hint, + }); + return; + } + default: { + assertUnreachable(resp) + } + } + } + } + return api.instance.updateBankAccount(state.token, bid, request) .then(onConfirm) .catch((error) => { setNotif({ -- cgit v1.2.3