gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated: Bank: error handling and amount parser


From: gnunet
Subject: [libeufin] branch master updated: Bank: error handling and amount parser.
Date: Wed, 13 Sep 2023 16:30:23 +0200

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

ms pushed a commit to branch master
in repository libeufin.

The following commit(s) were added to refs/heads/master by this push:
     new 4f8b94fa Bank: error handling and amount parser.
4f8b94fa is described below

commit 4f8b94faf1822d24ae1a4e9ece93bda2f797ab59
Author: MS <ms@taler.net>
AuthorDate: Wed Sep 13 16:26:33 2023 +0200

    Bank: error handling and amount parser.
    
    Ktor's StatusPages catches any Exception thrown in the application
    and try to build a Taler ErrorDetail to respond to the client.
---
 .idea/gradle.xml                                   |   1 +
 .idea/workspace.xml                                | 162 ++++++++++-----------
 .../src/main/kotlin/tech/libeufin/bank/Database.kt |   8 +-
 bank/src/main/kotlin/tech/libeufin/bank/Helpers.kt |  86 +++++++++++
 bank/src/main/kotlin/tech/libeufin/bank/Main.kt    | 128 +++++++++++++---
 bank/src/test/kotlin/AmountTest.kt                 |  20 +++
 bank/src/test/kotlin/DatabaseTest.kt               |   4 +
 bank/src/test/kotlin/LibeuFinApiTest.kt            |  18 ++-
 contrib/wallet-core                                |   2 +-
 util/src/test/kotlin/AmountTest.kt                 |  45 ------
 10 files changed, 315 insertions(+), 159 deletions(-)

diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index e1d33bca..7b700961 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -10,6 +10,7 @@
           <set>
             <option value="$PROJECT_DIR$" />
             <option value="$PROJECT_DIR$/bank" />
+            <option value="$PROJECT_DIR$/nexus" />
             <option value="$PROJECT_DIR$/util" />
           </set>
         </option>
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 12738e16..ccdc86c3 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -5,74 +5,16 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" id="9436eb1e-de48-4f11-8ff7-f359340cb458" 
name="Changes" comment="">
-      <change afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
-      <change 
afterPath="$PROJECT_DIR$/bank/src/test/kotlin/LibeuFinApiTest.kt" 
afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/$PRODUCT_WORKSPACE_FILE$" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/.gitignore" beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/codeStyles/Project.xml" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/codeStyles/codeStyleConfig.xml" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/dictionaries/dold.xml" 
beforeDir="false" />
+      <change 
afterPath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/Helpers.kt" 
afterDir="false" />
+      <change afterPath="$PROJECT_DIR$/bank/src/test/kotlin/AmountTest.kt" 
afterDir="false" />
       <change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" 
afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/.idea/inspectionProfiles/Project_Default.xml" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/kotlinc.xml" beforeDir="false" 
afterPath="$PROJECT_DIR$/.idea/kotlinc.xml" afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/.idea/libraries-with-intellij-classes.xml" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" 
afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/.idea/runConfigurations/SchedulingTest.xml" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/.idea/runConfigurations/run_sandbox.xml" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/.idea/runConfigurations/test_nexus.xml" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/.idea/runConfigurations/test_sandbox.xml" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/.idea/uiDesigner.xml" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/bank/README" beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/README" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/bank/build.gradle" beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/build.gradle" afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/CircuitApi.kt"
 beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/CircuitApi.kt" 
afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/ConversionService.kt"
 beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/ConversionService.kt"
 afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/DB.kt" 
beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/DB.kt" 
afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" 
afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
       <change 
beforePath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/Database.kt" 
beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/Database.kt" 
afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/EbicsProtocolBackend.kt"
 beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/EbicsProtocolBackend.kt"
 afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/Helpers.kt" 
beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/Helpers.kt" 
afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/JSON.kt" 
beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/JSON.kt" 
afterDir="false" />
       <change 
beforePath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/Main.kt" 
beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/Main.kt" 
afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/XMLEbicsConverter.kt"
 beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/XMLEbicsConverter.kt"
 afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/bankAccount.kt"
 beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/main/kotlin/tech/libeufin/bank/bankAccount.kt"
 afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/bank/src/main/resources/logback.xml" 
beforeDir="false" afterPath="$PROJECT_DIR$/bank/src/main/resources/logback.xml" 
afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/bank/src/test/kotlin/BalanceTest.kt" 
beforeDir="false" afterPath="$PROJECT_DIR$/bank/src/test/kotlin/BalanceTest.kt" 
afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/bank/src/test/kotlin/DBTest.kt" 
beforeDir="false" afterPath="$PROJECT_DIR$/bank/src/test/kotlin/DBTest.kt" 
afterDir="false" />
       <change beforePath="$PROJECT_DIR$/bank/src/test/kotlin/DatabaseTest.kt" 
beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/test/kotlin/DatabaseTest.kt" afterDir="false" 
/>
-      <change 
beforePath="$PROJECT_DIR$/bank/src/test/kotlin/EbicsErrorTest.kt" 
beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/test/kotlin/EbicsErrorTest.kt" 
afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/bank/src/test/kotlin/StringsTest.kt" 
beforeDir="false" afterPath="$PROJECT_DIR$/bank/src/test/kotlin/StringsTest.kt" 
afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/database-versioning/new/libeufin-bank-0001.sql" 
beforeDir="false" 
afterPath="$PROJECT_DIR$/database-versioning/new/libeufin-bank-0001.sql" 
afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/database-versioning/new/procedures.sql" 
beforeDir="false" 
afterPath="$PROJECT_DIR$/database-versioning/new/procedures.sql" 
afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/build.gradle" beforeDir="false" 
afterPath="$PROJECT_DIR$/nexus/build.gradle" afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/ConversionServiceTest.kt" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/DbEventTest.kt" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/EbicsTest.kt" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/Iso20022Test.kt" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/JsonTest.kt" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/LetterFormatTest.kt" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/MakeEnv.kt" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/NexusApiTest.kt" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/PainTest.kt" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/PostFinance.kt" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/SandboxAccessApiTest.kt" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/SandboxBankAccountTest.kt" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/SandboxCircuitApiTest.kt" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/SandboxLegacyApiTest.kt" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/SchedulingTest.kt" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/SplitString.kt" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/SubjectNormalization.kt" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/TalerTest.kt" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/XLibeufinBankTest.kt" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/nexus/src/test/kotlin/XPathTest.kt" 
beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/nexus/src/test/resources/iso20022-samples/camt.053/de.camt.053.001.02.xml"
 beforeDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/nexus/src/test/resources/logback-test.xml" 
beforeDir="false" />
-      <change beforePath="$PROJECT_DIR$/util/build.gradle" beforeDir="false" 
afterPath="$PROJECT_DIR$/util/build.gradle" afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/util/src/main/kotlin/Config.kt" 
beforeDir="false" afterPath="$PROJECT_DIR$/util/src/main/kotlin/Config.kt" 
afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/util/src/main/kotlin/DB.kt" 
beforeDir="false" afterPath="$PROJECT_DIR$/util/src/main/kotlin/DB.kt" 
afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/util/src/main/kotlin/HTTP.kt" 
beforeDir="false" afterPath="$PROJECT_DIR$/util/src/main/kotlin/HTTP.kt" 
afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/util/src/main/kotlin/iban.kt" 
beforeDir="false" afterPath="$PROJECT_DIR$/util/src/main/kotlin/iban.kt" 
afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/util/src/main/kotlin/startServer.kt" 
beforeDir="false" afterPath="$PROJECT_DIR$/util/src/main/kotlin/startServer.kt" 
afterDir="false" />
-      <change beforePath="$PROJECT_DIR$/util/src/main/kotlin/time.kt" 
beforeDir="false" afterPath="$PROJECT_DIR$/util/src/main/kotlin/time.kt" 
afterDir="false" />
-      <change 
beforePath="$PROJECT_DIR$/util/src/test/kotlin/StartServerTest.kt" 
beforeDir="false" />
+      <change 
beforePath="$PROJECT_DIR$/bank/src/test/kotlin/LibeuFinApiTest.kt" 
beforeDir="false" 
afterPath="$PROJECT_DIR$/bank/src/test/kotlin/LibeuFinApiTest.kt" 
afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/contrib/wallet-core" beforeDir="false" 
afterPath="$PROJECT_DIR$/contrib/wallet-core" afterDir="false" />
+      <change beforePath="$PROJECT_DIR$/util/src/test/kotlin/AmountTest.kt" 
beforeDir="false" />
     </list>
     <option name="SHOW_DIALOG" value="false" />
     <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -90,10 +32,28 @@
         <task path="$PROJECT_DIR$">
           <activation />
         </task>
-        <projects_view />
+        <projects_view>
+          <tree_state>
+            <expand>
+              <path>
+                <item name="" 
type="6a2764b6:ExternalProjectsStructure$RootNode" />
+                <item name="libeufin" type="f1a62948:ProjectNode" />
+              </path>
+            </expand>
+            <select />
+          </tree_state>
+        </projects_view>
       </state>
     </system>
   </component>
+  <component name="FileTemplateManagerImpl">
+    <option name="RECENT_TEMPLATES">
+      <list>
+        <option value="Kotlin Class" />
+        <option value="Kotlin File" />
+      </list>
+    </option>
+  </component>
   <component name="Git.Settings">
     <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
   </component>
@@ -108,11 +68,16 @@
   <component name="PropertiesComponent">{
   &quot;keyToString&quot;: {
     &quot;RunOnceActivity.OpenProjectViewOnStart&quot;: &quot;true&quot;,
-    &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;
+    &quot;RunOnceActivity.ShowReadmeOnStart&quot;: &quot;true&quot;,
+    &quot;project.structure.last.edited&quot;: &quot;Project&quot;,
+    &quot;project.structure.proportion&quot;: &quot;0.0&quot;,
+    &quot;project.structure.side.proportion&quot;: &quot;0.0&quot;,
+    &quot;settings.editor.selected.configurable&quot;: 
&quot;project.kotlinCompiler&quot;,
+    &quot;settings.editor.splitter.proportion&quot;: &quot;0.31419808&quot;
   }
 }</component>
-  <component name="RunManager" 
selected="Gradle.LibeuFinApiTest.createAccountTest">
-    <configuration name="DatabaseTest" type="GradleRunConfiguration" 
factoryName="Gradle" temporary="true">
+  <component name="RunManager" selected="Gradle.DatabaseTest.bankAccountTest">
+    <configuration name="AmountTest.parseAmountTest" 
type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
       <ExternalSystemSettings>
         <option name="executionName" />
         <option name="externalProjectPath" value="$PROJECT_DIR$" />
@@ -125,7 +90,7 @@
           <list>
             <option value=":bank:test" />
             <option value="--tests" />
-            <option value="&quot;DatabaseTest&quot;" />
+            <option value="&quot;AmountTest.parseAmountTest&quot;" />
           </list>
         </option>
         <option name="vmOptions" />
@@ -135,7 +100,7 @@
       <DebugAllEnabled>false</DebugAllEnabled>
       <method v="2" />
     </configuration>
-    <configuration name="DatabaseTest.bearerTokenTest" 
type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
+    <configuration name="AmountTest.parseTalerAmountTest" 
type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
       <ExternalSystemSettings>
         <option name="executionName" />
         <option name="externalProjectPath" value="$PROJECT_DIR$" />
@@ -148,7 +113,7 @@
           <list>
             <option value=":bank:test" />
             <option value="--tests" />
-            <option value="&quot;DatabaseTest.bearerTokenTest&quot;" />
+            <option value="&quot;AmountTest.parseTalerAmountTest&quot;" />
           </list>
         </option>
         <option name="vmOptions" />
@@ -158,7 +123,30 @@
       <DebugAllEnabled>false</DebugAllEnabled>
       <method v="2" />
     </configuration>
-    <configuration name="LibeuFinApiTest.createAccountTest" 
type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
+    <configuration name="DatabaseTest.bankAccountTest" 
type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
+      <ExternalSystemSettings>
+        <option name="executionName" />
+        <option name="externalProjectPath" value="$PROJECT_DIR$" />
+        <option name="externalSystemIdString" value="GRADLE" />
+        <option name="scriptParameters" value="" />
+        <option name="taskDescriptions">
+          <list />
+        </option>
+        <option name="taskNames">
+          <list>
+            <option value=":bank:test" />
+            <option value="--tests" />
+            <option value="&quot;DatabaseTest.bankAccountTest&quot;" />
+          </list>
+        </option>
+        <option name="vmOptions" />
+      </ExternalSystemSettings>
+      
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
+      
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
+      <DebugAllEnabled>false</DebugAllEnabled>
+      <method v="2" />
+    </configuration>
+    <configuration name="JsonTest.deserializationTest" 
type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
       <ExternalSystemSettings>
         <option name="executionName" />
         <option name="externalProjectPath" value="$PROJECT_DIR$" />
@@ -171,7 +159,7 @@
           <list>
             <option value=":bank:test" />
             <option value="--tests" />
-            <option value="&quot;LibeuFinApiTest.createAccountTest&quot;" />
+            <option value="&quot;JsonTest.deserializationTest&quot;" />
           </list>
         </option>
         <option name="vmOptions" />
@@ -181,39 +169,43 @@
       <DebugAllEnabled>false</DebugAllEnabled>
       <method v="2" />
     </configuration>
-    <configuration name="libeufin [dependencies]" 
type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
+    <configuration name="LibeuFinApiTest.createAccountTest" 
type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
       <ExternalSystemSettings>
         <option name="executionName" />
         <option name="externalProjectPath" value="$PROJECT_DIR$" />
         <option name="externalSystemIdString" value="GRADLE" />
-        <option name="scriptParameters" />
+        <option name="scriptParameters" value="--quiet" />
         <option name="taskDescriptions">
           <list />
         </option>
         <option name="taskNames">
           <list>
-            <option value="dependencies" />
+            <option value=":bank:test" />
+            <option value="--tests" />
+            <option value="&quot;LibeuFinApiTest.createAccountTest&quot;" />
           </list>
         </option>
         <option name="vmOptions" />
       </ExternalSystemSettings>
-      <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
+      
<ExternalSystemDebugServerProcess>false</ExternalSystemDebugServerProcess>
       
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
       <DebugAllEnabled>false</DebugAllEnabled>
       <method v="2" />
     </configuration>
     <list>
-      <item itemvalue="Gradle.libeufin [dependencies]" />
-      <item itemvalue="Gradle.DatabaseTest" />
-      <item itemvalue="Gradle.DatabaseTest.bearerTokenTest" />
+      <item itemvalue="Gradle.DatabaseTest.bankAccountTest" />
+      <item itemvalue="Gradle.AmountTest.parseTalerAmountTest" />
+      <item itemvalue="Gradle.AmountTest.parseAmountTest" />
+      <item itemvalue="Gradle.JsonTest.deserializationTest" />
       <item itemvalue="Gradle.LibeuFinApiTest.createAccountTest" />
     </list>
     <recent_temporary>
       <list>
+        <item itemvalue="Gradle.DatabaseTest.bankAccountTest" />
         <item itemvalue="Gradle.LibeuFinApiTest.createAccountTest" />
-        <item itemvalue="Gradle.libeufin [dependencies]" />
-        <item itemvalue="Gradle.DatabaseTest" />
-        <item itemvalue="Gradle.DatabaseTest.bearerTokenTest" />
+        <item itemvalue="Gradle.AmountTest.parseTalerAmountTest" />
+        <item itemvalue="Gradle.AmountTest.parseAmountTest" />
+        <item itemvalue="Gradle.JsonTest.deserializationTest" />
       </list>
     </recent_temporary>
   </component>
@@ -228,4 +220,8 @@
     </task>
     <servers />
   </component>
+  <component name="XSLT-Support.FileAssociations.UIState">
+    <expand />
+    <select />
+  </component>
 </project>
\ No newline at end of file
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Database.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
index 799788c0..2239a50c 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Database.kt
@@ -15,10 +15,10 @@ data class Customer(
     val passwordHash: String,
     val name: String,
     val dbRowId: Long? = null, // mostly used when retrieving records.
-    val email: String?,
-    val phone: String?,
-    val cashoutPayto: String?,
-    val cashoutCurrency: String?
+    val email: String? = null,
+    val phone: String? = null,
+    val cashoutPayto: String? = null,
+    val cashoutCurrency: String? = null
 )
 fun Customer.expectRowId(): Long = this.dbRowId ?: throw 
internalServerError("Cutsomer '${this.login}' had no DB row ID")
 
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Helpers.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/Helpers.kt
new file mode 100644
index 00000000..19b1150c
--- /dev/null
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Helpers.kt
@@ -0,0 +1,86 @@
+/*
+ * This file is part of LibEuFin.
+ * Copyright (C) 2019 Stanisci and Dold.
+
+ * LibEuFin is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3, or
+ * (at your option) any later version.
+
+ * LibEuFin is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
+ * Public License for more details.
+
+ * You should have received a copy of the GNU Affero General Public
+ * License along with LibEuFin; see the file COPYING.  If not, see
+ * <http://www.gnu.org/licenses/>
+ */
+
+package tech.libeufin.bank
+
+import io.ktor.http.*
+import tech.libeufin.util.getIban
+import java.lang.NumberFormatException
+
+// HELPERS.  FIXME: make unit tests for them.
+
+fun internalServerError(hint: String): LibeufinBankException =
+    LibeufinBankException(
+        httpStatus = HttpStatusCode.InternalServerError,
+        talerError = TalerError(
+            code = GENERIC_INTERNAL_INVARIANT_FAILURE,
+            hint = hint
+        )
+    )
+// Generates a new Payto-URI with IBAN scheme.
+fun genIbanPaytoUri(): String = "payto://iban/SANDBOXX/${getIban()}"
+
+fun parseTalerAmount(
+    amount: String,
+    fracDigits: FracDigits = FracDigits.EIGHT
+): TalerAmount {
+    val format = when (fracDigits) {
+        FracDigits.TWO ->
+            Pair("^([A-Z]+):([0-9])(\\.[0-9][0-9]?)?$", 100)
+        FracDigits.EIGHT ->
+            Pair(
+                
"^([A-Z]+):([0-9])(\\.[0-9][0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?)?\$",
+                100000000
+            )
+    }
+    val match = Regex(format.first).find(amount) ?: throw 
LibeufinBankException(
+        httpStatus = HttpStatusCode.BadRequest,
+        talerError = TalerError(
+            code = BANK_BAD_FORMAT_AMOUNT,
+            hint = "Invalid amount: $amount"
+        ))
+    val _value = match.destructured.component2()
+    // Fraction is at most 8 digits, so it's always < than MAX_INT.
+    val fraction: Int = match.destructured.component3().run {
+        var frac = 0
+        var power = format.second
+        if (this.isNotEmpty())
+            // Skips the dot and processes the fractional chars.
+            this.substring(1).forEach { chr ->
+                power /= 10
+                frac += power * chr.digitToInt()
+        }
+        return@run frac
+    }
+    val value: Long = try {
+        _value.toLong()
+    } catch (e: NumberFormatException) {
+        throw LibeufinBankException(
+            httpStatus = HttpStatusCode.BadRequest,
+            talerError = TalerError(
+                code = BANK_BAD_FORMAT_AMOUNT,
+                hint = "Invalid amount: ${amount}, could not extract the value 
part."
+            )
+        )
+    }
+    return TalerAmount(
+        value = value,
+        frac = fraction
+    )
+}
\ No newline at end of file
diff --git a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt 
b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
index 2662a051..2967732c 100644
--- a/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
+++ b/bank/src/main/kotlin/tech/libeufin/bank/Main.kt
@@ -1,3 +1,22 @@
+/*
+ * This file is part of LibEuFin.
+ * Copyright (C) 2019 Stanisci and Dold.
+
+ * LibEuFin is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation; either version 3, or
+ * (at your option) any later version.
+
+ * LibEuFin is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General
+ * Public License for more details.
+
+ * You should have received a copy of the GNU Affero General Public
+ * License along with LibEuFin; see the file COPYING.  If not, see
+ * <http://www.gnu.org/licenses/>
+ */
+
 package tech.libeufin.bank
 
 import io.ktor.http.*
@@ -22,11 +41,25 @@ import tech.libeufin.util.*
 // GLOBALS
 val logger: Logger = LoggerFactory.getLogger("tech.libeufin.bank")
 val db = Database(System.getProperty("BANK_DB_CONNECTION_STRING"))
+// fixme: make enum out of error codes.
 const val GENERIC_JSON_INVALID = 22
 const val GENERIC_PARAMETER_MALFORMED = 26
 const val GENERIC_PARAMETER_MISSING = 25
+const val BANK_UNMANAGED_EXCEPTION = 5110
+const val BANK_BAD_FORMAT_AMOUNT = 5108
+const val GENERIC_HTTP_HEADERS_MALFORMED = 23
+const val GENERIC_INTERNAL_INVARIANT_FAILURE = 60
+const val BANK_LOGIN_FAILED = 5105
+const val GENERIC_UNAUTHORIZED = 40
+const val GENERIC_UNDEFINED = -1 // Filler for ECs that don't exist yet.
 
 // TYPES
+
+enum class FracDigits(howMany: Int) {
+    TWO(2),
+    EIGHT(8)
+}
+
 @Serializable
 data class TalerError(
     val code: Int,
@@ -50,19 +83,11 @@ data class RegisterAccountRequest(
     val internal_payto_uri: String? = null
 )
 
-// Generates a new Payto-URI with IBAN scheme.
-fun genIbanPaytoUri(): String = "payto://iban/SANDBOXX/${getIban()}"
-fun parseTalerAmount(amount: String): TalerAmount {
-    val amountWithCurrencyRe = "^([A-Z]+):([0-9]+(\\.[0-9][0-9]?)?)$"
-    val match = Regex(amountWithCurrencyRe).find(amount) ?:
-    throw badRequest("Invalid amount")
-    val value = match.destructured.component2()
-    val fraction: Int = match.destructured.component3().run {
-        if (this.isEmpty()) return@run 0
-        return@run this.substring(1).toInt()
-    }
-    return TalerAmount(value.toLong(), fraction)
-}
+class LibeufinBankException(
+    val httpStatus: HttpStatusCode,
+    val talerError: TalerError
+) : Exception(talerError.hint)
+
 
 /**
  * Performs the HTTP basic authentication.  Returns the
@@ -79,7 +104,14 @@ fun doBasicAuth(encodedCredentials: String): Customer? {
          */
         limit = 2
     )
-    if (userAndPassSplit.size != 2) throw badRequest("Malformed Basic auth 
credentials found in the Authorization header.")
+    if (userAndPassSplit.size != 2)
+        throw LibeufinBankException(
+            httpStatus = HttpStatusCode.BadRequest,
+            talerError = TalerError(
+                code = GENERIC_HTTP_HEADERS_MALFORMED, // 23
+                "Malformed Basic auth credentials found in the Authorization 
header."
+            )
+        )
     val login = userAndPassSplit[0]
     val plainPassword = userAndPassSplit[1]
     return db.customerPwAuth(login, CryptoUtil.hashpw(plainPassword))
@@ -96,7 +128,12 @@ fun doTokenAuth(
     if (isExpired || maybeToken.scope != requiredScope) return null // FIXME: 
mention the reason?
     // Getting the related username.
     return db.customerGetFromRowId(maybeToken.bankCustomer)
-        ?: throw internalServerError("Customer not found, despite token 
mentions it.")
+        ?: throw LibeufinBankException(
+            httpStatus = HttpStatusCode.InternalServerError,
+            talerError = TalerError(
+                code = GENERIC_INTERNAL_INVARIANT_FAILURE,
+                hint = "Customer not found, despite token mentions it.",
+        ))
 }
 
 /**
@@ -115,7 +152,13 @@ fun ApplicationCall.myAuth(requiredScope: TokenScope): 
Customer? {
     return when (authDetails.scheme) {
         "Basic" -> doBasicAuth(authDetails.content)
         "Bearer" -> doTokenAuth(authDetails.content, requiredScope)
-        else -> throw badRequest("Authorization scheme '${authDetails.scheme}' 
is not supported.")
+        else -> throw LibeufinBankException(
+            httpStatus = HttpStatusCode.Unauthorized,
+            talerError = TalerError(
+                code = GENERIC_UNAUTHORIZED,
+                hint = "Authorization method wrong or not supported."
+            )
+        )
     }
 }
 
@@ -145,8 +188,15 @@ val webApp: Application.() -> Unit = {
     }
     install(RequestValidation)
     install(StatusPages) {
+        /**
+         * This branch triggers when the Ktor layers detect one
+         * invalid request.  It _might_ be thrown by the bank's
+         * actual logic, but that should be avoided because this
+         * (Ktor native) type doesn't easily map to the Taler error
+         * format.
+         */
         exception<BadRequestException> {call, cause ->
-            // Discouraged use, but the only helpful message.
+            // Discouraged use, but the only helpful message:
             var rootCause: Throwable? = cause.cause
             while (rootCause?.cause != null)
                 rootCause = rootCause.cause
@@ -158,12 +208,36 @@ val webApp: Application.() -> Unit = {
                 else -> GENERIC_JSON_INVALID // 22
             }
             call.respond(
-                HttpStatusCode.BadRequest,
-                TalerError(
+                status = HttpStatusCode.BadRequest,
+                message = TalerError(
                     code = talerErrorCode,
                     hint = rootCause?.message
                 ))
         }
+        /**
+         * This branch triggers when a bank handler throws it, and namely
+         * after one logical failure of the request(-handling).  This branch
+         * should be preferred to catch errors, as it allows to include the
+         * Taler specific error detail.
+         */
+        exception<LibeufinBankException> {call, cause ->
+            logger.error(cause.talerError.hint)
+            call.respond(
+                status = cause.httpStatus,
+                message = cause.talerError
+            )
+        }
+        // Catch-all branch to mean that the bank wasn't able to manage one 
error.
+        exception<Exception> {call, cause ->
+            logger.error(cause.message)
+            call.respond(
+                status = HttpStatusCode.InternalServerError,
+                message = TalerError(
+                    code = BANK_UNMANAGED_EXCEPTION,// 5110, bank's fault
+                    hint = cause.message
+                )
+            )
+        }
     }
     routing {
         post("/accounts") {
@@ -173,13 +247,25 @@ val webApp: Application.() -> Unit = {
                 val customer: Customer? = call.myAuth(TokenScope.readwrite)
                 if (customer == null || customer.login != "admin")
                     // OK to leak the only-admin policy here?
-                    throw unauthorized("Only admin allowed, and it failed to 
authenticate.")
+                    throw LibeufinBankException(
+                        httpStatus = HttpStatusCode.Unauthorized,
+                        talerError = TalerError(
+                            code = BANK_LOGIN_FAILED,
+                            hint = "Only admin allowed."
+                        )
+                    )
             }
             // auth passed, proceed with activity.
             val req = call.receive<RegisterAccountRequest>()
             // Prohibit reserved usernames:
             if (req.username == "admin" || req.username == "bank")
-                throw conflict("Username '${req.username}' is reserved.")
+                throw LibeufinBankException(
+                    httpStatus = HttpStatusCode.Conflict,
+                    talerError = TalerError(
+                        code = GENERIC_UNDEFINED, // FIXME: this waits GANA.
+                        hint = "Username '${req.username}' is reserved."
+                    )
+                )
             // Checking imdepotency.
             val maybeCustomerExists = db.customerGetFromLogin(req.username)
             // Can be null if previous call crashed before completion.
diff --git a/bank/src/test/kotlin/AmountTest.kt 
b/bank/src/test/kotlin/AmountTest.kt
new file mode 100644
index 00000000..2d8ffab0
--- /dev/null
+++ b/bank/src/test/kotlin/AmountTest.kt
@@ -0,0 +1,20 @@
+import org.junit.Test
+import tech.libeufin.bank.parseTalerAmount
+
+class AmountTest {
+    @Test
+    fun parseTalerAmountTest() {
+        val one = "EUR:1"
+        var obj = parseTalerAmount(one)
+        assert(obj.value == 1L && obj.frac == 0)
+        val onePointZero = "EUR:1.00"
+        obj = parseTalerAmount(onePointZero)
+        assert(obj.value == 1L && obj.frac == 0)
+        val onePointZeroOne = "EUR:1.01"
+        obj = parseTalerAmount(onePointZeroOne)
+        assert(obj.value == 1L && obj.frac == 1000000)
+        // Invalid tries
+        obj = parseTalerAmount("EUR:0.00000001")
+        assert(obj.value == 0L && obj.frac == 1)
+    }
+}
\ No newline at end of file
diff --git a/bank/src/test/kotlin/DatabaseTest.kt 
b/bank/src/test/kotlin/DatabaseTest.kt
index cb4755db..94f7aa67 100644
--- a/bank/src/test/kotlin/DatabaseTest.kt
+++ b/bank/src/test/kotlin/DatabaseTest.kt
@@ -41,6 +41,10 @@ class DatabaseTest {
     )
 
     fun initDb(): Database {
+        System.setProperty(
+            "BANK_DB_CONNECTION_STRING",
+            "jdbc:postgresql:///libeufincheck"
+        )
         execCommand(
             listOf(
                 "libeufin-bank-dbinit",
diff --git a/bank/src/test/kotlin/LibeuFinApiTest.kt 
b/bank/src/test/kotlin/LibeuFinApiTest.kt
index 501a447b..227af75f 100644
--- a/bank/src/test/kotlin/LibeuFinApiTest.kt
+++ b/bank/src/test/kotlin/LibeuFinApiTest.kt
@@ -4,6 +4,7 @@ import io.ktor.http.*
 import io.ktor.server.testing.*
 import kotlinx.serialization.json.Json
 import org.junit.Test
+import tech.libeufin.bank.Customer
 import tech.libeufin.bank.Database
 import tech.libeufin.bank.RegisterAccountRequest
 import tech.libeufin.bank.webApp
@@ -11,6 +12,10 @@ import tech.libeufin.util.execCommand
 
 class LibeuFinApiTest {
     fun initDb(): Database {
+        System.setProperty(
+            "BANK_DB_CONNECTION_STRING",
+            "jdbc:postgresql:///libeufincheck"
+        )
         execCommand(
             listOf(
                 "libeufin-bank-dbinit",
@@ -26,15 +31,17 @@ class LibeuFinApiTest {
     @Test
     fun createAccountTest() {
         testApplication {
-            System.setProperty(
-                "BANK_DB_CONNECTION_STRING",
-                "jdbc:postgresql:///libeufincheck"
-            )
             val db = initDb()
             db.configSet("max_debt_ordinary_customers", "KUDOS:11")
             db.configSet("only_admin_registrations", "yes")
+            db.customerCreate(Customer(
+                "admin",
+                "pass",
+                "CFO"
+            ))
             application(webApp)
-            client.post("/accounts") {
+            val resp = client.post("/accounts") {
+                expectSuccess = false
                 contentType(ContentType.Application.Json)
                 basicAuth("admin", "bar")
                 setBody("""{
@@ -43,6 +50,7 @@ class LibeuFinApiTest {
                     "name": "Jane"
                 }""".trimIndent())
             }
+            println("Resp status code: ${resp.status}")
         }
     }
 }
\ No newline at end of file
diff --git a/contrib/wallet-core b/contrib/wallet-core
index fa191419..c5a3cd4c 160000
--- a/contrib/wallet-core
+++ b/contrib/wallet-core
@@ -1 +1 @@
-Subproject commit fa191419fcf8cc4e2b17400b791dbdf4e673f5aa
+Subproject commit c5a3cd4c50676c49fa6c67cbdeb609101c38e764
diff --git a/util/src/test/kotlin/AmountTest.kt 
b/util/src/test/kotlin/AmountTest.kt
deleted file mode 100644
index 636c9060..00000000
--- a/util/src/test/kotlin/AmountTest.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-import io.ktor.util.reflect.*
-import org.junit.Test
-import tech.libeufin.util.isAmountZero
-import tech.libeufin.util.parseAmount
-import tech.libeufin.util.validatePlainAmount
-import java.math.BigDecimal
-import kotlin.reflect.typeOf
-
-inline fun <reified ExceptionType> assertException(block: () -> Unit) {
-    try {
-        block()
-    } catch (e: Throwable) {
-        assert(e.javaClass == ExceptionType::class.java)
-        return
-    }
-    return assert(false)
-}
-class AmountTest {
-    @Test
-    fun equalTest() {
-        assert(isAmountZero(BigDecimal("-0000000000.0000000000")))
-        assert(!isAmountZero(BigDecimal("1")))
-        assert(isAmountZero(BigDecimal("0.00")))
-        assert(isAmountZero(BigDecimal("0")))
-        assert(!isAmountZero(BigDecimal("00000000000001")))
-        assert(!isAmountZero(BigDecimal("-1.00000000")))
-    }
-
-    @Test
-    fun parse() {
-        var res = parseAmount("KUDOS:5.5")
-        assert(res.amount == "5.5")
-        assert(res.currency == "KUDOS")
-        assert(validatePlainAmount("1.0"))
-        assert(validatePlainAmount("1.00"))
-        assert(!validatePlainAmount("1.000"))
-        res = parseAmount("TESTKUDOS:1.11")
-        assert(res.amount == "1.11")
-        assert(res.currency == "TESTKUDOS")
-        assertException<UtilError> { parseAmount("TESTKUDOS:1.") }
-        assertException<UtilError> { parseAmount("TESTKUDOS:.1") }
-        assertException<UtilError> { parseAmount("TESTKUDOS:1.000") }
-        assertException<UtilError> { parseAmount("TESTKUDOS:1..") }
-    }
-}
\ No newline at end of file

-- 
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]