gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated (9df2547cc -> 03d3cce82)


From: gnunet
Subject: [taler-wallet-core] branch master updated (9df2547cc -> 03d3cce82)
Date: Wed, 26 Apr 2023 19:20:25 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a change to branch master
in repository wallet-core.

    from 9df2547cc fix endpoint
     new 982fc51a9 missing input type
     new 03d3cce82 fix #6363, breaking with merchant backend that accounts 
implemented

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../src/components/form/FormProvider.tsx           |   6 +
 .../form/InputPaytoForm.stories.tsx}               |  23 ++-
 .../src/components/form/InputPaytoForm.tsx         | 202 ++++++++++++++++++---
 .../components/index.stories.ts}                   |   2 +
 .../instance/DefaultInstanceFormFields.tsx         |   2 +-
 .../merchant-backoffice-ui/src/declaration.d.ts    |  55 +++++-
 .../src/paths/admin/create/CreatePage.tsx          |  12 +-
 .../paths/instance/templates/create/CreatePage.tsx |   1 +
 .../src/paths/instance/update/UpdatePage.tsx       |  25 ++-
 packages/merchant-backoffice-ui/src/stories.tsx    |   3 +-
 10 files changed, 277 insertions(+), 54 deletions(-)
 copy 
packages/merchant-backoffice-ui/src/{paths/instance/templates/update/Update.stories.tsx
 => components/form/InputPaytoForm.stories.tsx} (57%)
 copy packages/merchant-backoffice-ui/{copyleft-header.js => 
src/components/index.stories.ts} (92%)

diff --git 
a/packages/merchant-backoffice-ui/src/components/form/FormProvider.tsx 
b/packages/merchant-backoffice-ui/src/components/form/FormProvider.tsx
index 7bcebd706..0d53c4d08 100644
--- a/packages/merchant-backoffice-ui/src/components/form/FormProvider.tsx
+++ b/packages/merchant-backoffice-ui/src/components/form/FormProvider.tsx
@@ -82,6 +82,12 @@ export interface FormType<T> {
 
 const FormContext = createContext<FormType<unknown>>(null!);
 
+/**
+ * FIXME:
+ * USE MEMORY EVENTS INSTEAD OF CONTEXT
+ * @deprecated
+ */
+
 export function useFormContext<T>() {
   return useContext<FormType<T>>(FormContext);
 }
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/Update.stories.tsx
 
b/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.stories.tsx
similarity index 57%
copy from 
packages/merchant-backoffice-ui/src/paths/instance/templates/update/Update.stories.tsx
copy to 
packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.stories.tsx
index 8d07cb31f..2c1961639 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/Update.stories.tsx
+++ 
b/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.stories.tsx
@@ -19,14 +19,29 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { h, VNode, FunctionalComponent } from "preact";
-import { UpdatePage as TestedComponent } from "./UpdatePage.js";
+import { h } from "preact";
+import { tests } from "@gnu-taler/web-util/lib/index.browser";
+import { InputPaytoForm } from "./InputPaytoForm.js";
+import { FormProvider } from "./FormProvider.js";
+import { useState } from "preact/hooks";
 
 export default {
-  title: "Pages/Templates/Update",
-  component: TestedComponent,
+  title: "Components/Form/PayTo",
+  component: InputPaytoForm,
   argTypes: {
     onUpdate: { action: "onUpdate" },
     onBack: { action: "onBack" },
   },
 };
+
+export const Example = tests.createExample(() => {
+  const initial = {
+    accounts: [],
+  };
+  const [form, updateForm] = useState<Partial<typeof initial>>(initial);
+  return (
+    <FormProvider valueHandler={updateForm} object={form}>
+      <InputPaytoForm name="accounts" label="Accounts:" />
+    </FormProvider>
+  );
+}, {});
diff --git 
a/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx 
b/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx
index 3cd36a6e0..98fe2f91a 100644
--- a/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx
+++ b/packages/merchant-backoffice-ui/src/components/form/InputPaytoForm.tsx
@@ -28,6 +28,8 @@ import { Input } from "./Input.js";
 import { InputGroup } from "./InputGroup.js";
 import { InputSelector } from "./InputSelector.js";
 import { InputProps, useField } from "./useField.js";
+import { InputWithAddon } from "./InputWithAddon.js";
+import { MerchantBackend } from "../../declaration.js";
 
 export interface Props<T> extends InputProps<T> {
   isValid?: (e: any) => boolean;
@@ -50,6 +52,13 @@ type Entity = {
     instruction?: string;
     [name: string]: string | undefined;
   };
+  auth: {
+    type: "unset" | "basic" | "none";
+    url?: string;
+    username?: string;
+    password?: string;
+    repeat?: string;
+  };
 };
 
 function isEthereumAddress(address: string) {
@@ -162,8 +171,15 @@ const targets = [
   "bitcoin",
   "ethereum",
 ];
+const accountAuthType = ["none", "basic"];
 const noTargetValue = targets[0];
-const defaultTarget = { target: noTargetValue, options: {} };
+const defaultTarget: Partial<Entity> = {
+  target: noTargetValue,
+  options: {},
+  auth: {
+    type: "unset" as const,
+  },
+};
 
 export function InputPaytoForm<T>({
   name,
@@ -187,7 +203,7 @@ export function InputPaytoForm<T>({
   }
   const { i18n } = useTranslationContext();
 
-  const ops = value.options!;
+  const ops = value.options ?? {};
   const url = tryUrl(`payto://${value.target}${payToPath}`);
   if (url) {
     Object.keys(ops).forEach((opt_key) => {
@@ -222,6 +238,24 @@ export function InputPaytoForm<T>({
         ? i18n.str`required`
         : undefined,
     }),
+    auth: !value.auth
+      ? undefined
+      : undefinedIfEmpty({
+          username:
+            value.auth.type === "basic" && !value.auth.username
+              ? i18n.str`required`
+              : undefined,
+          password:
+            value.auth.type === "basic" && !value.auth.password
+              ? i18n.str`required`
+              : undefined,
+          repeat:
+            value.auth.type === "basic" && !value.auth.repeat
+              ? i18n.str`required`
+              : value.auth.repeat !== value.auth.password
+              ? i18n.str`is not the same`
+              : undefined,
+        }),
   };
 
   const hasErrors = Object.keys(errors).some(
@@ -229,10 +263,31 @@ export function InputPaytoForm<T>({
   );
 
   const submit = useCallback((): void => {
+    const accounts: MerchantBackend.Instances.MerchantBankAccount[] = paytos;
     const alreadyExists =
-      paytos.findIndex((x: string) => x === paytoURL) !== -1;
+      accounts.findIndex((x) => x.payto_uri === paytoURL) !== -1;
     if (!alreadyExists) {
-      onChange([paytoURL, ...paytos] as any);
+      const newValue: MerchantBackend.Instances.MerchantBankAccount = {
+        payto_uri: paytoURL,
+      };
+      if (value.auth) {
+        if (value.auth.url) {
+          newValue.credit_facade_url = value.auth.url;
+        }
+        if (value.auth.type === "none") {
+          newValue.credit_facade_credentials = {
+            type: "none",
+          };
+        }
+        if (value.auth.type === "basic") {
+          newValue.credit_facade_credentials = {
+            type: "basic",
+            username: value.auth.username ?? "",
+            password: value.auth.password ?? "",
+          };
+        }
+      }
+      onChange([newValue, ...accounts] as any);
     }
     valueHandler(defaultTarget);
   }, [value]);
@@ -339,37 +394,126 @@ export function InputPaytoForm<T>({
           </Fragment>
         )}
 
+        {/**
+         * Show additional fields apart from the payto
+         */}
         {value.target !== noTargetValue && (
-          <Input
-            name="options.receiver-name"
-            label={i18n.str`Name`}
-            tooltip={i18n.str`Bank account owner's name.`}
-          />
-        )}
+          <Fragment>
+            <Input
+              name="options.receiver-name"
+              label={i18n.str`Name`}
+              tooltip={i18n.str`Bank account owner's name.`}
+            />
+            <InputWithAddon
+              name="auth.url"
+              label={i18n.str`Account info URL`}
+              help="https://bank.com";
+              expand
+              tooltip={i18n.str`From where the merchant can download 
information about incoming wire transfers to this account`}
+            />
+            <InputSelector
+              name="auth.type"
+              label={i18n.str`Auth type`}
+              tooltip={i18n.str`Choose the authentication type for the account 
info URL`}
+              values={accountAuthType}
+              toStr={(str) => {
+                // if (str === "unset") {
+                //   return "Without change";
+                // }
+                if (str === "none") return "Without authentication";
+                return "Username and password";
+              }}
+            />
+            {value.auth?.type === "basic" ? (
+              <Fragment>
+                <Input
+                  name="auth.username"
+                  label={i18n.str`Username`}
+                  tooltip={i18n.str`Username to access the account 
information.`}
+                />
+                <Input
+                  name="auth.password"
+                  inputType="password"
+                  label={i18n.str`Password`}
+                  tooltip={i18n.str`Password to access the account 
information.`}
+                />
+                <Input
+                  name="auth.repeat"
+                  inputType="password"
+                  label={i18n.str`Repeat password`}
+                />
+              </Fragment>
+            ) : undefined}
 
+            {/* <InputWithAddon
+              name="options.credit_credentials"
+              label={i18n.str`Account info`}
+              inputType={showKey ? "text" : "password"}
+              help="From where the merchant can download information about 
incoming wire transfers to this account"
+              expand
+              tooltip={i18n.str`Useful to validate the purchase`}
+              fromStr={(v) => v.toUpperCase()}
+              addonAfter={
+                <span class="icon">
+                  {showKey ? (
+                    <i class="mdi mdi-eye" />
+                  ) : (
+                    <i class="mdi mdi-eye-off" />
+                  )}
+                </span>
+              }
+              side={
+                <span style={{ display: "flex" }}>
+                  <button
+                    data-tooltip={
+                      showKey
+                        ? i18n.str`show secret key`
+                        : i18n.str`hide secret key`
+                    }
+                    class="button is-info mr-3"
+                    onClick={(e) => {
+                      setShowKey(!showKey);
+                    }}
+                  >
+                    {showKey ? (
+                      <i18n.Translate>hide</i18n.Translate>
+                    ) : (
+                      <i18n.Translate>show</i18n.Translate>
+                    )}
+                  </button>
+                </span>
+              }
+            /> */}
+          </Fragment>
+        )}
+        {/**
+         * Show the values in the list
+         */}
         <div class="field is-horizontal">
           <div class="field-label is-normal" />
           <div class="field-body" style={{ display: "block" }}>
-            {paytos.map((v: any, i: number) => (
-              <div
-                key={i}
-                class="tags has-addons mt-3 mb-0 mr-3"
-                style={{ flexWrap: "nowrap" }}
-              >
-                <span
-                  class="tag is-medium is-info mb-0"
-                  style={{ maxWidth: "90%" }}
+            {paytos.map(
+              (v: MerchantBackend.Instances.MerchantBankAccount, i: number) => 
(
+                <div
+                  key={i}
+                  class="tags has-addons mt-3 mb-0 mr-3"
+                  style={{ flexWrap: "nowrap" }}
                 >
-                  {v}
-                </span>
-                <a
-                  class="tag is-medium is-danger is-delete mb-0"
-                  onClick={() => {
-                    onChange(paytos.filter((f: any) => f !== v) as any);
-                  }}
-                />
-              </div>
-            ))}
+                  <span
+                    class="tag is-medium is-info mb-0"
+                    style={{ maxWidth: "90%" }}
+                  >
+                    {v.payto_uri}
+                  </span>
+                  <a
+                    class="tag is-medium is-danger is-delete mb-0"
+                    onClick={() => {
+                      onChange(paytos.filter((f: any) => f !== v) as any);
+                    }}
+                  />
+                </div>
+              ),
+            )}
             {!paytos.length && i18n.str`No accounts yet.`}
             {required && (
               <span class="icon has-text-danger is-right">
diff --git a/packages/merchant-backoffice-ui/copyleft-header.js 
b/packages/merchant-backoffice-ui/src/components/index.stories.ts
similarity index 92%
copy from packages/merchant-backoffice-ui/copyleft-header.js
copy to packages/merchant-backoffice-ui/src/components/index.stories.ts
index f0d755a0e..c57ddab14 100644
--- a/packages/merchant-backoffice-ui/copyleft-header.js
+++ b/packages/merchant-backoffice-ui/src/components/index.stories.ts
@@ -13,3 +13,5 @@
  You should have received a copy of the GNU General Public License along with
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
+
+export * as payto from "./form/InputPaytoForm.stories.js";
diff --git 
a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
 
b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
index 3a3bdd6f3..bbdc9708a 100644
--- 
a/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
+++ 
b/packages/merchant-backoffice-ui/src/components/instance/DefaultInstanceFormFields.tsx
@@ -86,7 +86,7 @@ export function DefaultInstanceFormFields({
       />
 
       <InputPaytoForm<Entity>
-        name="payto_uris"
+        name="accounts"
         label={i18n.str`Bank account`}
         tooltip={i18n.str`URI specifying bank account for crediting revenue.`}
       />
diff --git a/packages/merchant-backoffice-ui/src/declaration.d.ts 
b/packages/merchant-backoffice-ui/src/declaration.d.ts
index b21af32d1..58e14a114 100644
--- a/packages/merchant-backoffice-ui/src/declaration.d.ts
+++ b/packages/merchant-backoffice-ui/src/declaration.d.ts
@@ -262,15 +262,45 @@ export namespace MerchantBackend {
       // header.
       token?: string;
     }
+    type FacadeCredentials = NoFacadeCredentials | BasicAuthFacadeCredentials;
+
+    interface NoFacadeCredentials {
+      type: "none";
+    }
+
+    interface BasicAuthFacadeCredentials {
+      type: "basic";
+
+      // Username to use to authenticate
+      username: string;
+
+      // Password to use to authenticate
+      password: string;
+    }
+
+    interface MerchantBankAccount {
+      // The payto:// URI where the wallet will send coins.
+      payto_uri: string;
+
+      // Optional base URL for a facade where the
+      // merchant backend can see incoming wire
+      // transfers to reconcile its accounting
+      // with that of the exchange. Used by
+      // taler-merchant-wirewatch.
+      credit_facade_url?: string;
+
+      // Credentials for accessing the credit facade.
+      credit_facade_credentials?: FacadeCredentials;
+    }
     //POST /private/instances
     interface InstanceConfigurationMessage {
-      // The URI where the wallet will send coins.  A merchant may have
+      // Bank accounts of the merchant.  A merchant may have
       // multiple accounts, thus this is an array.  Note that by
-      // removing URIs from this list the respective account is set to
+      // removing accounts from this list the respective account is set to
       // inactive and thus unavailable for new contracts, but preserved
       // in the database as existing offers and contracts may still refer
       // to it.
-      payto_uris: string[];
+      accounts: MerchantBankAccount[];
 
       // Name of the merchant instance to create (will become $INSTANCE).
       id: string;
@@ -326,10 +356,11 @@ export namespace MerchantBackend {
 
     // PATCH /private/instances/$INSTANCE
     interface InstanceReconfigurationMessage {
-      // The URI where the wallet will send coins.  A merchant may have
-      // multiple accounts, thus this is an array.  Note that by
-      // removing URIs from this list
-      payto_uris: string[];
+      // Bank accounts of the merchant.  A merchant may have
+      // multiple accounts, thus this is an array.  Note that removing
+      // URIs from this list deactivates the specified accounts
+      // (they will no longer be used for future contracts).
+      accounts: MerchantBankAccount[];
 
       // Merchant name corresponding to this instance.
       name: string;
@@ -491,6 +522,16 @@ export namespace MerchantBackend {
       // salt used to compute h_wire
       salt: HashCode;
 
+      // URL from where the merchant can download information
+      // about incoming wire transfers to this account.
+      credit_facade_url?: string;
+
+      // Credentials to use when accessing the credit facade.
+      // Never returned on a GET (as this may be somewhat
+      // sensitive data). Can be set in POST
+      // or PATCH requests to update (or delete) credentials.
+      credit_facade_credentials?: FacadeCredentials;
+
       // true if this account is active,
       // false if it is historic.
       active: boolean;
diff --git 
a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx 
b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
index 0ef1f1270..4087908a2 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/create/CreatePage.tsx
@@ -47,7 +47,7 @@ interface Props {
 function with_defaults(id?: string): Partial<Entity> {
   return {
     id,
-    payto_uris: [],
+    accounts: [],
     user_type: "business",
     default_pay_delay: { d_us: 2 * 1000 * 60 * 60 * 1000 }, // two hours
     default_wire_fee_amortization: 1,
@@ -75,12 +75,14 @@ export function CreatePage({ onCreate, onBack, forceId }: 
Props): VNode {
       : value.user_type !== "business" && value.user_type !== "individual"
       ? i18n.str`should be business or individual`
       : undefined,
-    payto_uris:
-      !value.payto_uris || !value.payto_uris.length
+    accounts:
+      !value.accounts || !value.accounts.length
         ? i18n.str`required`
         : undefinedIfEmpty(
-            value.payto_uris.map((p) => {
-              return !PAYTO_REGEX.test(p) ? i18n.str`is not valid` : undefined;
+            value.accounts.map((p) => {
+              return !PAYTO_REGEX.test(p.payto_uri)
+                ? i18n.str`is not valid`
+                : undefined;
             }),
           ),
     default_max_deposit_fee: !value.default_max_deposit_fee
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
index f6aa9a9ae..51ceee45d 100644
--- 
a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
+++ 
b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
@@ -178,6 +178,7 @@ export function CreatePage({ onCreate, onBack }: Props): 
VNode {
                 <InputWithAddon<Entity>
                   name="pos_key"
                   label={i18n.str`Point-of-sale key`}
+                  inputType={showKey ? "text" : "password"}
                   help="Be sure to be very hard to guess or use the random 
generator"
                   tooltip={i18n.str`Useful to validate the purchase`}
                   fromStr={(v) => v.toUpperCase()}
diff --git 
a/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx 
b/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx
index 2b57ab429..ecf6e2ae5 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/update/UpdatePage.tsx
@@ -53,14 +53,23 @@ interface Props {
 function convert(
   from: MerchantBackend.Instances.QueryInstancesResponse,
 ): Entity {
-  const { accounts, ...rest } = from;
-  const payto_uris = accounts.filter((a) => a.active).map((a) => a.payto_uri);
+  const { accounts: qAccounts, ...rest } = from;
+  const accounts = qAccounts
+    .filter((a) => a.active)
+    .map(
+      (a) =>
+        ({
+          payto_uri: a.payto_uri,
+          credit_facade_url: a.credit_facade_url,
+          credit_facade_credentials: a.credit_facade_credentials,
+        } as MerchantBackend.Instances.MerchantBankAccount),
+    );
   const defaults = {
     default_wire_fee_amortization: 1,
     default_pay_delay: { d_us: 2 * 1000 * 1000 * 60 * 60 }, //two hours
     default_wire_transfer_delay: { d_us: 2 * 1000 * 1000 * 60 * 60 * 2 }, 
//two hours
   };
-  return { ...defaults, ...rest, payto_uris };
+  return { ...defaults, ...rest, accounts };
 }
 
 function getTokenValuePart(t?: string): string | undefined {
@@ -103,12 +112,14 @@ export function UpdatePage({
       : value.user_type !== "business" && value.user_type !== "individual"
       ? i18n.str`should be business or individual`
       : undefined,
-    payto_uris:
-      !value.payto_uris || !value.payto_uris.length
+    accounts:
+      !value.accounts || !value.accounts.length
         ? i18n.str`required`
         : undefinedIfEmpty(
-            value.payto_uris.map((p) => {
-              return !PAYTO_REGEX.test(p) ? i18n.str`is not valid` : undefined;
+            value.accounts.map((p) => {
+              return !PAYTO_REGEX.test(p.payto_uri)
+                ? i18n.str`is not valid`
+                : undefined;
             }),
           ),
     default_max_deposit_fee: !value.default_max_deposit_fee
diff --git a/packages/merchant-backoffice-ui/src/stories.tsx 
b/packages/merchant-backoffice-ui/src/stories.tsx
index ccfde4ef2..2c61e5586 100644
--- a/packages/merchant-backoffice-ui/src/stories.tsx
+++ b/packages/merchant-backoffice-ui/src/stories.tsx
@@ -22,6 +22,7 @@ import { strings } from "./i18n/strings.js";
 
 import * as admin from "./paths/admin/index.stories.js";
 import * as instance from "./paths/instance/index.stories.js";
+import * as components from "./components/index.stories.js";
 
 import { renderStories } from "@gnu-taler/web-util/lib/index.browser";
 
@@ -33,7 +34,7 @@ function SortStories(a: any, b: any): number {
 
 function main(): void {
   renderStories(
-    { admin, instance },
+    { admin, instance, components },
     {
       strings,
     },

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]