gnunet-svn
[Top][All Lists]
Advanced

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

[libeufin] branch master updated (1fe2687a -> a105222b)


From: gnunet
Subject: [libeufin] branch master updated (1fe2687a -> a105222b)
Date: Tue, 13 Jun 2023 14:57:27 +0200

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

ms pushed a change to branch master
in repository libeufin.

    from 1fe2687a Creating missing Sandbox table.
     new 22a2824f DB migration building blocks.
     new a105222b indentation

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:
 Makefile                                           |  15 +-
 contrib/indent-sql-sh                              |  39 +++
 contrib/libeufin-load-sql                          |  91 +++++++
 database-versioning/nexus-0001.sql                 | 241 +++++++++++++++++
 database-versioning/sandbox-0001.sql               | 250 ++++++++++++++++++
 database-versioning/versioning.sql                 | 293 +++++++++++++++++++++
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  |   4 +-
 util/src/main/kotlin/DB.kt                         |  12 +
 .../Errors.kt => util/src/main/kotlin/exec.kt      |  34 ++-
 9 files changed, 953 insertions(+), 26 deletions(-)
 create mode 100755 contrib/indent-sql-sh
 create mode 100755 contrib/libeufin-load-sql
 create mode 100644 database-versioning/nexus-0001.sql
 create mode 100644 database-versioning/sandbox-0001.sql
 create mode 100644 database-versioning/versioning.sql
 copy nexus/src/main/kotlin/tech/libeufin/nexus/Errors.kt => 
util/src/main/kotlin/exec.kt (58%)

diff --git a/Makefile b/Makefile
index 6fdbfaff..1d96dac8 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ include build-system/config.mk
 escaped_pwd = $(shell pwd | sed 's/\//\\\//g')
 
 all: assemble
-install: install-nexus install-sandbox install-cli
+install: install-nexus install-sandbox install-cli install-db-versioning
 git-archive-all = 
./build-system/taler-build-scripts/archive-with-submodules/git_archive_all.py
 git_tag=$(shell git describe --tags)
 gradle_version=$(shell ./gradlew -q libeufinVersion)
@@ -35,7 +35,6 @@ get-spa:
 deb: exec-arch copy-spa
        @dpkg-buildpackage -rfakeroot -b -uc -us
 
-
 .PHONY: install-sandbox
 install-sandbox:
        @./gradlew -q -Pprefix=$(prefix) sandbox:installToPrefix; cd ..
@@ -49,6 +48,13 @@ install-cli:
        @./gradlew -q replaceVersionCli
        @install -D cli/bin/libeufin-cli $(prefix)/bin
 
+.PHONY: install-db-versioning
+install-db-versioning:
+       $(eval LOAD_SQL_SCRIPT_NAME := libeufin-load-sql)
+       @sed "s|__STATIC_PATCHES_LOCATION__|$(prefix)/share/libeufin/sql|" < 
contrib/$(LOAD_SQL_SCRIPT_NAME) > build/$(LOAD_SQL_SCRIPT_NAME)
+       @install -D database-versioning/*.sql -t $(prefix)/share/libeufin/sql
+       @install -D build/$(LOAD_SQL_SCRIPT_NAME) -t $(prefix)/bin
+
 .PHONY: assemble
 assemble:
        @./gradlew assemble
@@ -61,8 +67,3 @@ check:
 check-cli:
        @cd ./cli/tests && ./circuit_test.sh
        @cd ./cli/tests && ./debit_test.sh
-
-
-# .PHONY: parse
-# parse:
-#      @cd parsing-tests; py.test -s checks.py
diff --git a/contrib/indent-sql-sh b/contrib/indent-sql-sh
new file mode 100755
index 00000000..d702859d
--- /dev/null
+++ b/contrib/indent-sql-sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+set -eu
+
+# This script indents the output of Exposed SQL logger.
+
+# Usage: ./indent.sh filename
+
+# Remove leading "^SQL: " that Exposed uses.
+crop_leading_sql () {
+  sed 's/^SQL: //'
+}
+
+# Inserts new line & two spaces before the first "("
+# and last ")", and before each comma.  Only triggers on
+# "CREATE TABLE"-lines.
+indent_create_table () {
+  sed '/^CREATE/s/, /,/g' \
+  | sed '/^CREATE/s/\(,\|)$\)/\n  \1/g' \
+  | sed '/^CREATE/s/(/\n  (/'
+}
+
+
+# Inserts new line & two spaces before each "ALTER TABLE"
+# statement
+indent_alter_table () {
+  sed 's/^ALTER TABLE \(.*\)/ALTER TABLE\n  \1/'
+}
+
+# Inserts a blank line after between each CREATE/ALTER TABLE statement.
+blank_line_after_statement () {
+  sed '/^CREATE TABLE/s/\(.*\)/\n\1/' \
+  | sed '/^ALTER TABLE/s/\(.*\)/\n\1/'
+}
+
+crop_leading_sql < $1 \
+  | indent_create_table \
+  | indent_alter_table \
+  | blank_line_after_statement
diff --git a/contrib/libeufin-load-sql b/contrib/libeufin-load-sql
new file mode 100755
index 00000000..eaf3e534
--- /dev/null
+++ b/contrib/libeufin-load-sql
@@ -0,0 +1,91 @@
+#!/bin/bash
+
+set -eu
+
+# The only CLI argument is 'nexus' or 'sandbox',
+# indicating which service will get its database prepared.
+
+fail () {
+  echo $1
+  exit 1
+}
+
+run_sql_file () {
+  # -q doesn't hide all the output, hence the
+  # redirection to /dev/null.
+  psql -d $DB_CONNECTION \
+    -q \
+    -f $1 \
+    --set ON_ERROR_STOP=1 > /dev/null
+}
+
+# The real check happens (by the caller)
+# by checking the returned text.
+check_patch_applied () {
+  psql -d $DB_CONNECTION \
+  -t \
+  -c "SELECT applied_by FROM _v.patches WHERE patch_name = '$1' LIMIT 1"
+}
+
+# Iterates over the .sql migration files and applies
+# the new ones.
+iterate_over_patches () {
+  if test "$1" != sandbox -a "$1" != nexus; then
+    fail "iterate_over_patches: only 'sandbox' and 'nexus' are acceptable 
arguments."
+  fi
+  component="$1"
+  cd $PATCHES_LOCATION
+  for patch_filename in $(ls -1 -v $component-[0-9][0-9][0-9][0-9].sql); do
+    patch_name=$(echo $patch_filename | cut -f1 -d.)
+    echo Checking patch: "$patch_name"
+    maybe_applied=$(check_patch_applied "$patch_name")
+    if test -n "$maybe_applied"; then continue; fi
+    # patch not applied, apply it.
+    echo Patch $patch_name not applied, applying it.
+    run_sql_file $patch_filename
+  done
+  cd - > /dev/null # cd to previous location.
+}
+while getopts ":d:l:h" OPTION; do
+  case "$OPTION" in 
+    d)
+      DB_CONNECTION="$OPTARG"
+      ;;
+    l)
+      PATCHES_LOCATION="$OPTARG"
+      ;;
+    s)
+      SERVICE="${OPTARG:-}"
+      ;;
+    h)
+      echo Usage: libeufin-load-sql OPTIONS
+      echo
+      echo 'Supported options:'
+      echo "  -s SERVICE  -- specify 'sandbox' or 'nexus', according to which 
set of tables are to be setup.  If missing both sets will be setup on the same 
database."
+      echo '  -d DB_CONN  -- required.  Pass DB_CONN as the postgres 
connection string.  Passed verbatim to Psql'
+      echo '  -l LOC      -- required.  Pass LOC as the SQL files location.  
Typically $prefix/share/libeufin/sql'
+      echo '  -h           -- print this help'
+      exit 0
+      ;;
+    ?)
+      fail 'Unrecognized command line option'
+    ;;
+  esac
+done
+
+# Checking required options.
+if test -z "${PATCHES_LOCATION:-}"; then
+  # This value is substituted by GNU make at installation time.
+  PATCHES_LOCATION=__STATIC_PATCHES_LOCATION__
+fi
+if test -z "${DB_CONNECTION:-}"; then
+  fail "Required option '-d' was missing."
+fi
+
+run_sql_file "$PATCHES_LOCATION/versioning.sql"
+if test -z "${SERVICE:-}"; then # both table sets.
+  iterate_over_patches sandbox
+  iterate_over_patches nexus
+  exit 0
+fi
+iterate_over_patches $SERVICE # helper checks the argument sanity.
diff --git a/database-versioning/nexus-0001.sql 
b/database-versioning/nexus-0001.sql
new file mode 100644
index 00000000..c18a909f
--- /dev/null
+++ b/database-versioning/nexus-0001.sql
@@ -0,0 +1,241 @@
+-- Compatible with LibEuFin version: 1fe2687aaf696c8566367fe7ed082f1d78e6b78d
+
+BEGIN;
+
+SELECT _v.register_patch('nexus-0001', NULL, NULL);
+
+CREATE TABLE IF NOT EXISTS nexususers 
+  (id BIGSERIAL PRIMARY KEY
+  ,username TEXT NOT NULL
+  ,"password" TEXT NOT NULL
+  ,superuser BOOLEAN NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS nexusbankconnections 
+  (id BIGSERIAL PRIMARY KEY
+  ,"connectionId" TEXT NOT NULL
+  ,"type" TEXT NOT NULL
+  ,dialect TEXT NULL
+  ,"user" BIGINT NOT NULL
+  ,CONSTRAINT fk_nexusbankconnections_user_id FOREIGN KEY ("user") REFERENCES 
nexususers(id) ON DELETE RESTRICT ON UPDATE RESTRICT
+  );
+
+CREATE TABLE IF NOT EXISTS xlibeufinbankusers 
+  (id BIGSERIAL PRIMARY KEY
+  ,username TEXT NOT NULL
+  ,"password" TEXT NOT NULL
+  ,"baseUrl" TEXT NOT NULL
+  ,"nexusBankConnection" BIGINT NOT NULL
+  ,CONSTRAINT fk_xlibeufinbankusers_nexusbankconnection_id FOREIGN KEY 
("nexusBankConnection") REFERENCES nexusbankconnections(id) ON DELETE RESTRICT 
ON UPDATE RESTRICT
+  );
+
+CREATE TABLE IF NOT EXISTS nexusscheduledtasks 
+  (id BIGSERIAL PRIMARY KEY
+  ,"resourceType" TEXT NOT NULL
+  ,"resourceId" TEXT NOT NULL
+  ,"taskName" TEXT NOT NULL
+  ,"taskType" TEXT NOT NULL
+  ,"taskCronspec" TEXT NOT NULL
+  ,"taskParams" TEXT NOT NULL
+  ,"nextScheduledExecutionSec" BIGINT NULL
+  ,"lastScheduledExecutionSec" BIGINT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS nexusbankaccounts 
+  (id BIGSERIAL PRIMARY KEY
+  ,"bankAccountId" TEXT NOT NULL
+  ,"accountHolder" TEXT NOT NULL
+  ,iban TEXT NOT NULL
+  ,"bankCode" TEXT NOT NULL
+  ,"defaultBankConnection" BIGINT NULL
+  ,"lastStatementCreationTimestamp" BIGINT NULL
+  ,"lastReportCreationTimestamp" BIGINT NULL
+  ,"lastNotificationCreationTimestamp" BIGINT NULL
+  ,"highestSeenBankMessageSerialId" BIGINT NOT NULL
+  ,pain001counter BIGINT DEFAULT 1 NOT NULL
+  ,CONSTRAINT fk_nexusbankaccounts_defaultbankconnection_id FOREIGN KEY 
("defaultBankConnection") REFERENCES nexusbankconnections(id) ON DELETE 
RESTRICT ON UPDATE RESTRICT
+  );
+
+ALTER TABLE
+  nexusbankaccounts ADD CONSTRAINT nexusbankaccounts_bankaccountid_unique 
UNIQUE ("bankAccountId");
+
+CREATE TABLE IF NOT EXISTS nexusbanktransactions 
+  (id BIGSERIAL PRIMARY KEY
+  ,"accountTransactionId" TEXT NOT NULL
+  ,"bankAccount" BIGINT NOT NULL
+  ,"creditDebitIndicator" TEXT NOT NULL
+  ,currency TEXT NOT NULL
+  ,amount TEXT NOT NULL
+  ,status VARCHAR(16) NOT NULL
+  ,"updatedBy" BIGINT NULL
+  ,"transactionJson" TEXT NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS paymentinitiations 
+  (id BIGSERIAL PRIMARY KEY
+  ,"bankAccount" BIGINT NOT NULL
+  ,"preparationDate" BIGINT NOT NULL
+  ,"submissionDate" BIGINT NULL
+  ,"sum" TEXT NOT NULL
+  ,currency TEXT NOT NULL
+  ,"endToEndId" TEXT NOT NULL
+  ,"paymentInformationId" TEXT NOT NULL
+  ,"instructionId" TEXT NOT NULL
+  ,subject TEXT NOT NULL
+  ,"creditorIban" TEXT NOT NULL
+  ,"creditorBic" TEXT NULL
+  ,"creditorName" TEXT NOT NULL
+  ,submitted BOOLEAN DEFAULT false NOT NULL
+  ,invalid BOOLEAN NULL
+  ,"messageId" TEXT NOT NULL
+  ,"rawConfirmation" BIGINT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS nexusebicssubscribers 
+  (id BIGSERIAL PRIMARY KEY
+  ,"ebicsURL" TEXT NOT NULL
+  ,"hostID" TEXT NOT NULL
+  ,"partnerID" TEXT NOT NULL
+  ,"userID" TEXT NOT NULL
+  ,"systemID" TEXT NULL
+  ,"signaturePrivateKey" bytea NOT NULL
+  ,"encryptionPrivateKey" bytea NOT NULL
+  ,"authenticationPrivateKey" bytea NOT NULL
+  ,"bankEncryptionPublicKey" bytea NULL
+  ,"bankAuthenticationPublicKey" bytea NULL
+  ,"nexusBankConnection" BIGINT NOT NULL
+  ,"ebicsIniState" VARCHAR(16) NOT NULL
+  ,"ebicsHiaState" VARCHAR(16) NOT NULL
+  ,CONSTRAINT fk_nexusebicssubscribers_nexusbankconnection_id FOREIGN KEY 
("nexusBankConnection") REFERENCES nexusbankconnections(id) ON DELETE RESTRICT 
ON UPDATE RESTRICT
+  );
+
+CREATE TABLE IF NOT EXISTS nexusbankbalances 
+  (id BIGSERIAL PRIMARY KEY
+  ,balance TEXT NOT NULL
+  ,"creditDebitIndicator" TEXT NOT NULL
+  ,"bankAccount" BIGINT NOT NULL
+  ,"date" TEXT NOT NULL
+  ,CONSTRAINT fk_nexusbankbalances_bankaccount_id FOREIGN KEY ("bankAccount") 
REFERENCES nexusbankaccounts(id) ON DELETE RESTRICT ON UPDATE RESTRICT
+  );
+
+CREATE TABLE IF NOT EXISTS anastasisincomingpayments 
+  (id BIGSERIAL PRIMARY KEY
+  ,payment BIGINT NOT NULL
+  ,subject TEXT NOT NULL
+  ,"timestampMs" BIGINT NOT NULL
+  ,"incomingPaytoUri" TEXT NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS talerincomingpayments 
+  (id BIGSERIAL PRIMARY KEY
+  ,payment BIGINT NOT NULL
+  ,"reservePublicKey" TEXT NOT NULL
+  ,"timestampMs" BIGINT NOT NULL
+  ,"incomingPaytoUri" TEXT NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS facades 
+  (id BIGSERIAL PRIMARY KEY
+  ,"facadeName" TEXT NOT NULL
+  ,"type" TEXT NOT NULL
+  ,creator BIGINT NOT NULL
+  ,CONSTRAINT fk_facades_creator_id FOREIGN KEY (creator) REFERENCES 
nexususers(id) ON DELETE RESTRICT ON UPDATE RESTRICT
+  );
+
+ALTER TABLE
+  facades ADD CONSTRAINT facades_facadename_unique UNIQUE ("facadeName");
+
+CREATE TABLE IF NOT EXISTS talerrequestedpayments 
+  (id BIGSERIAL PRIMARY KEY
+  ,facade BIGINT NOT NULL
+  ,payment BIGINT NOT NULL
+  ,"requestUid" TEXT NOT NULL
+  ,amount TEXT NOT NULL
+  ,"exchangeBaseUrl" TEXT NOT NULL
+  ,wtid TEXT NOT NULL
+  ,"creditAccount" TEXT NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS facadestate 
+  (id BIGSERIAL PRIMARY KEY
+  ,"bankAccount" TEXT NOT NULL
+  ,"bankConnection" TEXT NOT NULL
+  ,currency TEXT NOT NULL
+  ,"reserveTransferLevel" TEXT NOT NULL
+  ,facade BIGINT NOT NULL
+  ,"highestSeenMessageSerialId" BIGINT DEFAULT 0 NOT NULL
+  ,CONSTRAINT fk_facadestate_facade_id FOREIGN KEY (facade) REFERENCES 
facades(id) ON DELETE CASCADE ON UPDATE RESTRICT
+  );
+
+CREATE TABLE IF NOT EXISTS talerinvalidincomingpayments 
+  (id BIGSERIAL PRIMARY KEY
+  ,payment BIGINT NOT NULL
+  ,"timestampMs" BIGINT NOT NULL
+  ,refunded BOOLEAN DEFAULT false NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS nexusbankmessages 
+  (id BIGSERIAL PRIMARY KEY
+  ,"bankConnection" BIGINT NOT NULL
+  ,message bytea NOT NULL
+  ,"messageId" TEXT NULL
+  ,"fetchLevel" VARCHAR(16) NOT NULL
+  ,errors BOOLEAN DEFAULT false NOT NULL
+  ,CONSTRAINT fk_nexusbankmessages_bankconnection_id FOREIGN KEY 
("bankConnection") REFERENCES nexusbankconnections(id) ON DELETE RESTRICT ON 
UPDATE RESTRICT
+  );
+
+CREATE TABLE IF NOT EXISTS offeredbankaccounts 
+  (id BIGSERIAL PRIMARY KEY
+  ,"offeredAccountId" TEXT NOT NULL
+  ,"bankConnection" BIGINT NOT NULL
+  ,iban TEXT NOT NULL
+  ,"bankCode" TEXT NOT NULL
+  ,"holderName" TEXT NOT NULL
+  ,imported BIGINT NULL
+  ,CONSTRAINT fk_offeredbankaccounts_bankconnection_id FOREIGN KEY 
("bankConnection") REFERENCES nexusbankconnections(id) ON DELETE RESTRICT ON 
UPDATE RESTRICT
+  ,CONSTRAINT fk_offeredbankaccounts_imported_id FOREIGN KEY (imported) 
REFERENCES nexusbankaccounts(id) ON DELETE RESTRICT ON UPDATE RESTRICT
+  );
+
+ALTER TABLE
+  offeredbankaccounts ADD CONSTRAINT 
offeredbankaccounts_offeredaccountid_bankconnection_unique UNIQUE 
("offeredAccountId", "bankConnection");
+
+CREATE TABLE IF NOT EXISTS nexuspermissions 
+  (id BIGSERIAL PRIMARY KEY
+  ,"resourceType" TEXT NOT NULL
+  ,"resourceId" TEXT NOT NULL
+  ,"subjectType" TEXT NOT NULL
+  ,"subjectName" TEXT NOT NULL
+  ,"permissionName" TEXT NOT NULL
+  );
+
+ALTER TABLE
+  nexuspermissions ADD CONSTRAINT 
nexuspermissions_resourcetype_resourceid_subjecttype_subjectnam UNIQUE 
("resourceType", "resourceId", "subjectType", "subjectName", "permissionName");
+
+ALTER TABLE
+  nexusbanktransactions ADD CONSTRAINT fk_nexusbanktransactions_bankaccount_id 
FOREIGN KEY ("bankAccount") REFERENCES nexusbankaccounts(id) ON DELETE RESTRICT 
ON UPDATE RESTRICT;
+
+ALTER TABLE
+  nexusbanktransactions ADD CONSTRAINT fk_nexusbanktransactions_updatedby_id 
FOREIGN KEY ("updatedBy") REFERENCES nexusbanktransactions(id) ON DELETE 
RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  paymentinitiations ADD CONSTRAINT fk_paymentinitiations_bankaccount_id 
FOREIGN KEY ("bankAccount") REFERENCES nexusbankaccounts(id) ON DELETE RESTRICT 
ON UPDATE RESTRICT;
+
+ALTER TABLE
+  paymentinitiations ADD CONSTRAINT fk_paymentinitiations_rawconfirmation_id 
FOREIGN KEY ("rawConfirmation") REFERENCES nexusbanktransactions(id) ON DELETE 
RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  anastasisincomingpayments ADD CONSTRAINT 
fk_anastasisincomingpayments_payment_id FOREIGN KEY (payment) REFERENCES 
nexusbanktransactions(id) ON DELETE RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  talerincomingpayments ADD CONSTRAINT fk_talerincomingpayments_payment_id 
FOREIGN KEY (payment) REFERENCES nexusbanktransactions(id) ON DELETE RESTRICT 
ON UPDATE RESTRICT;
+
+ALTER TABLE
+  talerrequestedpayments ADD CONSTRAINT fk_talerrequestedpayments_facade_id 
FOREIGN KEY (facade) REFERENCES facades(id) ON DELETE RESTRICT ON UPDATE 
RESTRICT;
+
+ALTER TABLE
+  talerrequestedpayments ADD CONSTRAINT fk_talerrequestedpayments_payment_id 
FOREIGN KEY (payment) REFERENCES paymentinitiations(id) ON DELETE RESTRICT ON 
UPDATE RESTRICT;
+
+ALTER TABLE
+  talerinvalidincomingpayments ADD CONSTRAINT 
fk_talerinvalidincomingpayments_payment_id FOREIGN KEY (payment) REFERENCES 
nexusbanktransactions(id) ON DELETE RESTRICT ON UPDATE RESTRICT;
+
+COMMIT
diff --git a/database-versioning/sandbox-0001.sql 
b/database-versioning/sandbox-0001.sql
new file mode 100644
index 00000000..b6ed53ef
--- /dev/null
+++ b/database-versioning/sandbox-0001.sql
@@ -0,0 +1,250 @@
+-- Compatible with LibEuFin version: 1fe2687aaf696c8566367fe7ed082f1d78e6b78d
+
+BEGIN;
+
+SELECT _v.register_patch('sandbox-0001', NULL, NULL);
+
+CREATE TABLE IF NOT EXISTS demobankconfigs 
+  (id BIGSERIAL PRIMARY KEY
+  ,hostname TEXT NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS bankaccounts 
+  (id SERIAL PRIMARY KEY
+  ,iban TEXT NOT NULL
+  ,bic TEXT DEFAULT 'SANDBOXX' NOT NULL
+  ,"label" TEXT NOT NULL
+  ,"owner" TEXT NOT NULL
+  ,"isPublic" BOOLEAN DEFAULT false NOT NULL
+  ,"demoBank" BIGINT NOT NULL
+  ,"lastTransaction" BIGINT NULL
+  ,"lastFiatSubmission" BIGINT NULL
+  ,"lastFiatFetch" TEXT DEFAULT '0' NOT NULL
+  );
+
+ALTER TABLE
+  bankaccounts ADD CONSTRAINT accountLabelIndex UNIQUE ("label");
+
+CREATE TABLE IF NOT EXISTS bankaccounttransactions 
+  (id BIGSERIAL PRIMARY KEY
+  ,"creditorIban" TEXT NOT NULL
+  ,"creditorBic" TEXT NULL
+  ,"creditorName" TEXT NOT NULL
+  ,"debtorIban" TEXT NOT NULL
+  ,"debtorBic" TEXT NULL
+  ,"debtorName" TEXT NOT NULL
+  ,subject TEXT NOT NULL
+  ,amount TEXT NOT NULL
+  ,currency TEXT NOT NULL
+  ,"date" BIGINT NOT NULL
+  ,"accountServicerReference" TEXT NOT NULL
+  ,"pmtInfId" TEXT NULL
+  ,"EndToEndId" TEXT NULL
+  ,direction TEXT NOT NULL
+  ,account INT NOT NULL
+  ,demobank BIGINT NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS cashoutsubmissions 
+  (id BIGSERIAL PRIMARY KEY
+  ,"localTransaction" BIGINT NOT NULL
+  ,"maybeNexusResponse" TEXT NULL
+  ,"submissionTime" BIGINT NULL
+  );
+
+ALTER TABLE
+  cashoutsubmissions ADD CONSTRAINT cashoutsubmissions_localtransaction_unique 
UNIQUE ("localTransaction");
+
+CREATE TABLE IF NOT EXISTS demobankconfigpairs 
+  (id BIGSERIAL PRIMARY KEY
+  ,"demobankName" TEXT NOT NULL
+  ,"configKey" TEXT NOT NULL
+  ,"configValue" TEXT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS ebicssubscribers 
+  (id SERIAL PRIMARY KEY
+  ,"userID" TEXT NOT NULL
+  ,"partnerID" TEXT NOT NULL
+  ,"systemID" TEXT NULL
+  ,"hostID" TEXT NOT NULL
+  ,"signatureKey" INT NULL
+  ,"encryptionKey" INT NULL
+  ,"authorizationKey" INT NULL
+  ,"nextOrderID" INT NOT NULL
+  ,"state" INT NOT NULL
+  ,"bankAccount" INT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS ebicssubscriberpublickeys
+  (id SERIAL PRIMARY KEY
+   ,"rsaPublicKey" bytea NOT NULL
+   ,"state" INT NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS ebicshosts 
+  (id SERIAL PRIMARY KEY
+  ,"hostID" TEXT NOT NULL
+  ,"ebicsVersion" TEXT NOT NULL
+  ,"signaturePrivateKey" bytea NOT NULL
+  ,"encryptionPrivateKey" bytea NOT NULL
+  ,"authenticationPrivateKey" bytea NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS ebicsdownloadtransactions 
+  ("transactionID" TEXT NOT NULL
+  ,"orderType" TEXT NOT NULL
+  ,host INT NOT NULL
+  ,subscriber INT NOT NULL
+  ,"encodedResponse" TEXT NOT NULL
+  ,"transactionKeyEnc" bytea NOT NULL
+  ,"numSegments" INT NOT NULL
+  ,"segmentSize" INT NOT NULL
+  ,"receiptReceived" BOOLEAN NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS ebicsuploadtransactions 
+  ("transactionID" TEXT NOT NULL
+  ,"orderType" TEXT NOT NULL
+  ,"orderID" TEXT NOT NULL
+  ,host INT NOT NULL
+  ,subscriber INT NOT NULL
+  ,"numSegments" INT NOT NULL
+  ,"lastSeenSegment" INT NOT NULL
+  ,"transactionKeyEnc" bytea NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS ebicsuploadtransactionchunks 
+  ("transactionID" TEXT NOT NULL
+  ,"chunkIndex" INT NOT NULL
+  ,"chunkContent" bytea NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS ebicsordersignatures 
+  (id SERIAL PRIMARY KEY
+  ,"orderID" TEXT NOT NULL
+  ,"orderType" TEXT NOT NULL
+  ,"partnerID" TEXT NOT NULL
+  ,"userID" TEXT NOT NULL
+  ,"signatureAlgorithm" TEXT NOT NULL
+  ,"signatureValue" bytea NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS bankaccountfreshtransactions 
+  (id BIGSERIAL PRIMARY KEY
+  ,"transaction" BIGINT NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS bankaccountreports 
+  (id SERIAL PRIMARY KEY
+  ,"reportId" TEXT NOT NULL
+  ,"creationTime" BIGINT NOT NULL
+  ,"xmlMessage" TEXT NOT NULL
+  ,"bankAccount" INT NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS bankaccountstatements 
+  (id SERIAL PRIMARY KEY
+  ,"statementId" TEXT NOT NULL
+  ,"creationTime" BIGINT NOT NULL
+  ,"xmlMessage" TEXT NOT NULL
+  ,"bankAccount" INT NOT NULL
+  ,"balanceClbd" TEXT NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS talerwithdrawals 
+  (id BIGSERIAL PRIMARY KEY
+  ,wopid uuid NOT NULL
+  ,amount TEXT NOT NULL
+  ,"selectionDone" BOOLEAN DEFAULT false NOT NULL
+  ,aborted BOOLEAN DEFAULT false NOT NULL
+  ,"confirmationDone" BOOLEAN DEFAULT false NOT NULL
+  ,"reservePub" TEXT NULL
+  ,"selectedExchangePayto" TEXT NULL
+  ,"walletBankAccount" INT NOT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS demobankcustomers 
+  (id BIGSERIAL PRIMARY KEY
+  ,username TEXT NOT NULL
+  ,"passwordHash" TEXT NOT NULL
+  ,"name" TEXT NULL
+  ,email TEXT NULL
+  ,phone TEXT NULL
+  ,cashout_address TEXT NULL
+  );
+
+CREATE TABLE IF NOT EXISTS cashoutoperations 
+  (id BIGSERIAL PRIMARY KEY
+  ,uuid uuid NOT NULL
+  ,"amountDebit" TEXT NOT NULL
+  ,"amountCredit" TEXT NOT NULL
+  ,"buyAtRatio" TEXT NOT NULL
+  ,"buyInFee" TEXT NOT NULL
+  ,"sellAtRatio" TEXT NOT NULL
+  ,"sellOutFee" TEXT NOT NULL
+  ,subject TEXT NOT NULL
+  ,"creationTime" BIGINT NOT NULL
+  ,"confirmationTime" BIGINT NULL
+  ,"tanChannel" INT NOT NULL
+  ,account TEXT NOT NULL
+  ,"cashoutAddress" TEXT NOT NULL
+  ,tan TEXT NOT NULL
+  ,status INT DEFAULT 1 NOT NULL
+  );
+
+ALTER TABLE
+  bankaccounts ADD CONSTRAINT fk_bankaccounts_demobank_id FOREIGN KEY 
("demoBank") REFERENCES demobankconfigs(id) ON DELETE RESTRICT ON UPDATE 
RESTRICT;
+
+ALTER TABLE
+  bankaccounts ADD CONSTRAINT fk_bankaccounts_lasttransaction_id FOREIGN KEY 
("lastTransaction") REFERENCES bankaccounttransactions(id) ON DELETE RESTRICT 
ON UPDATE RESTRICT;
+
+ALTER TABLE
+  bankaccounts ADD CONSTRAINT fk_bankaccounts_lastfiatsubmission_id FOREIGN 
KEY ("lastFiatSubmission") REFERENCES bankaccounttransactions(id) ON DELETE 
RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  bankaccounttransactions ADD CONSTRAINT fk_bankaccounttransactions_account_id 
FOREIGN KEY (account) REFERENCES bankaccounts(id) ON DELETE CASCADE ON UPDATE 
RESTRICT;
+
+ALTER TABLE
+  bankaccounttransactions ADD CONSTRAINT 
fk_bankaccounttransactions_demobank_id FOREIGN KEY (demobank) REFERENCES 
demobankconfigs(id) ON DELETE RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  cashoutsubmissions ADD CONSTRAINT fk_cashoutsubmissions_localtransaction_id 
FOREIGN KEY ("localTransaction") REFERENCES bankaccounttransactions(id) ON 
DELETE RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  ebicssubscribers ADD CONSTRAINT fk_ebicssubscribers_signaturekey_id FOREIGN 
KEY ("signatureKey") REFERENCES ebicssubscriberpublickeys(id) ON DELETE 
RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  ebicssubscribers ADD CONSTRAINT fk_ebicssubscribers_encryptionkey_id FOREIGN 
KEY ("encryptionKey") REFERENCES ebicssubscriberpublickeys(id) ON DELETE 
RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  ebicssubscribers ADD CONSTRAINT fk_ebicssubscribers_authorizationkey_id 
FOREIGN KEY ("authorizationKey") REFERENCES ebicssubscriberpublickeys(id) ON 
DELETE RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  ebicssubscribers ADD CONSTRAINT fk_ebicssubscribers_bankaccount_id FOREIGN 
KEY ("bankAccount") REFERENCES bankaccounts(id) ON DELETE CASCADE ON UPDATE 
RESTRICT;
+
+ALTER TABLE
+  ebicsdownloadtransactions ADD CONSTRAINT 
fk_ebicsdownloadtransactions_host_id FOREIGN KEY (host) REFERENCES 
ebicshosts(id) ON DELETE RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  ebicsdownloadtransactions ADD CONSTRAINT 
fk_ebicsdownloadtransactions_subscriber_id FOREIGN KEY (subscriber) REFERENCES 
ebicssubscribers(id) ON DELETE RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  ebicsuploadtransactions ADD CONSTRAINT fk_ebicsuploadtransactions_host_id 
FOREIGN KEY (host) REFERENCES ebicshosts(id) ON DELETE RESTRICT ON UPDATE 
RESTRICT;
+
+ALTER TABLE
+  ebicsuploadtransactions ADD CONSTRAINT 
fk_ebicsuploadtransactions_subscriber_id FOREIGN KEY (subscriber) REFERENCES 
ebicssubscribers(id) ON DELETE RESTRICT ON UPDATE RESTRICT;
+
+ALTER TABLE
+  bankaccountfreshtransactions ADD CONSTRAINT 
fk_bankaccountfreshtransactions_transaction_id FOREIGN KEY ("transaction") 
REFERENCES bankaccounttransactions(id) ON DELETE CASCADE ON UPDATE RESTRICT;
+
+ALTER TABLE
+  bankaccountreports ADD CONSTRAINT fk_bankaccountreports_bankaccount_id 
FOREIGN KEY ("bankAccount") REFERENCES bankaccounts(id) ON DELETE RESTRICT ON 
UPDATE RESTRICT;
+
+ALTER TABLE
+  bankaccountstatements ADD CONSTRAINT fk_bankaccountstatements_bankaccount_id 
FOREIGN KEY ("bankAccount") REFERENCES bankaccounts(id) ON DELETE RESTRICT ON 
UPDATE RESTRICT;
+
+ALTER TABLE
+  talerwithdrawals ADD CONSTRAINT fk_talerwithdrawals_walletbankaccount_id 
FOREIGN KEY ("walletBankAccount") REFERENCES bankaccounts(id) ON DELETE 
RESTRICT ON UPDATE RESTRICT;
+
+COMMIT;
diff --git a/database-versioning/versioning.sql 
b/database-versioning/versioning.sql
new file mode 100644
index 00000000..98e7f661
--- /dev/null
+++ b/database-versioning/versioning.sql
@@ -0,0 +1,293 @@
+-- LICENSE AND COPYRIGHT
+--
+-- Copyright (C) 2010 Hubert depesz Lubaczewski
+--
+-- This program is distributed under the (Revised) BSD License:
+-- L<http://www.opensource.org/licenses/bsd-license.php>
+--
+-- Redistribution and use in source and binary forms, with or without
+-- modification, are permitted provided that the following conditions
+-- are met:
+--
+-- * Redistributions of source code must retain the above copyright
+-- notice, this list of conditions and the following disclaimer.
+--
+-- * Redistributions in binary form must reproduce the above copyright
+--   notice, this list of conditions and the following disclaimer in the
+--   documentation and/or other materials provided with the distribution.
+--
+-- * Neither the name of Hubert depesz Lubaczewski's Organization
+--   nor the names of its contributors may be used to endorse or
+--   promote products derived from this software without specific
+--   prior written permission.
+--
+-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
ARE
+-- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+-- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+-- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
LIABILITY,
+-- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 
USE
+-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+--
+-- Code origin: 
https://gitlab.com/depesz/Versioning/blob/master/install.versioning.sql
+--
+--
+-- # NAME
+--
+-- **Versioning** - simplistic take on tracking and applying changes to 
databases.
+--
+-- # DESCRIPTION
+--
+-- This project strives to provide simple way to manage changes to
+-- database.
+--
+-- Instead of making changes on development server, then finding
+-- differences between production and development, deciding which ones
+-- should be installed on production, and finding a way to install them -
+-- you start with writing diffs themselves!
+--
+-- # INSTALLATION
+--
+-- To install versioning simply run install.versioning.sql in your database
+-- (all of them: production, stage, test, devel, ...).
+--
+-- # USAGE
+--
+-- In your files with patches to database, put whole logic in single
+-- transaction, and use \_v.\* functions - usually \_v.register_patch() at
+-- least to make sure everything is OK.
+--
+-- For example. Let's assume you have patch files:
+--
+-- ## 0001.sql:
+--
+-- ```
+-- create table users (id serial primary key, username text);
+-- ```
+--
+-- ## 0002.sql:
+--
+-- ```
+-- insert into users (username) values ('depesz');
+-- ```
+-- To change it to use versioning you would change the files, to this
+-- state:
+--
+-- 0000.sql:
+--
+-- ```
+-- BEGIN;
+-- select _v.register_patch('000-base', NULL, NULL);
+-- create table users (id serial primary key, username text);
+-- COMMIT;
+-- ```
+--
+-- ## 0002.sql:
+--
+-- ```
+-- BEGIN;
+-- select _v.register_patch('001-users', ARRAY['000-base'], NULL);
+-- insert into users (username) values ('depesz');
+-- COMMIT;
+-- ```
+--
+-- This will make sure that patch 001-users can only be applied after
+-- 000-base.
+--
+-- # AVAILABLE FUNCTIONS
+--
+-- ## \_v.register_patch( TEXT )
+--
+-- Registers named patch, or dies if it is already registered.
+--
+-- Returns integer which is id of patch in \_v.patches table - only if it
+-- succeeded.
+--
+-- ## \_v.register_patch( TEXT, TEXT[] )
+--
+-- Same as \_v.register_patch( TEXT ), but checks is all given patches (given 
as
+-- array in second argument) are already registered.
+--
+-- ## \_v.register_patch( TEXT, TEXT[], TEXT[] )
+--
+-- Same as \_v.register_patch( TEXT, TEXT[] ), but also checks if there are no 
conflicts with preexisting patches.
+--
+-- Third argument is array of names of patches that conflict with current one. 
So
+-- if any of them is installed - register_patch will error out.
+--
+-- ## \_v.unregister_patch( TEXT )
+--
+-- Removes information about given patch from the versioning data.
+--
+-- It doesn't remove objects that were created by this patch - just removes
+-- metainformation.
+--
+-- ## \_v.assert_user_is_superuser()
+--
+-- Make sure that current patch is being loaded by superuser.
+--
+-- If it's not - it will raise exception, and break transaction.
+--
+-- ## \_v.assert_user_is_not_superuser()
+--
+-- Make sure that current patch is not being loaded by superuser.
+--
+-- If it is - it will raise exception, and break transaction.
+--
+-- ## \_v.assert_user_is_one_of(TEXT, TEXT, ... )
+--
+-- Make sure that current patch is being loaded by one of listed users.
+--
+-- If ```current_user``` is not listed as one of arguments - function will 
raise
+-- exception and break the transaction.
+
+BEGIN;
+
+-- This file adds versioning support to database it will be loaded to.
+-- It requires that PL/pgSQL is already loaded - will raise exception 
otherwise.
+-- All versioning "stuff" (tables, functions) is in "_v" schema.
+
+-- All functions are defined as 'RETURNS SETOF INT4' to be able to make them 
to RETURN literally nothing (0 rows).
+-- >> RETURNS VOID<< IS similar, but it still outputs "empty line" in psql 
when calling.
+CREATE SCHEMA IF NOT EXISTS _v;
+COMMENT ON SCHEMA _v IS 'Schema for versioning data and functionality.';
+
+CREATE TABLE IF NOT EXISTS _v.patches (
+    patch_name  TEXT        PRIMARY KEY,
+    applied_tsz TIMESTAMPTZ NOT NULL DEFAULT now(),
+    applied_by  TEXT        NOT NULL,
+    requires    TEXT[],
+    conflicts   TEXT[]
+);
+COMMENT ON TABLE _v.patches              IS 'Contains information about what 
patches are currently applied on database.';
+COMMENT ON COLUMN _v.patches.patch_name  IS 'Name of patch, has to be unique 
for every patch.';
+COMMENT ON COLUMN _v.patches.applied_tsz IS 'When the patch was applied.';
+COMMENT ON COLUMN _v.patches.applied_by  IS 'Who applied this patch 
(PostgreSQL username)';
+COMMENT ON COLUMN _v.patches.requires    IS 'List of patches that are required 
for given patch.';
+COMMENT ON COLUMN _v.patches.conflicts   IS 'List of patches that conflict 
with given patch.';
+
+CREATE OR REPLACE FUNCTION _v.register_patch( IN in_patch_name TEXT, IN 
in_requirements TEXT[], in_conflicts TEXT[], OUT versioning INT4 ) RETURNS 
setof INT4 AS $$
+DECLARE
+    t_text   TEXT;
+    t_text_a TEXT[];
+    i INT4;
+BEGIN
+    -- Thanks to this we know only one patch will be applied at a time
+    LOCK TABLE _v.patches IN EXCLUSIVE MODE;
+
+    SELECT patch_name INTO t_text FROM _v.patches WHERE patch_name = 
in_patch_name;
+    IF FOUND THEN
+        RAISE EXCEPTION 'Patch % is already applied!', in_patch_name;
+    END IF;
+
+    t_text_a := ARRAY( SELECT patch_name FROM _v.patches WHERE patch_name = 
any( in_conflicts ) );
+    IF array_upper( t_text_a, 1 ) IS NOT NULL THEN
+        RAISE EXCEPTION 'Versioning patches conflict. Conflicting patche(s) 
installed: %.', array_to_string( t_text_a, ', ' );
+    END IF;
+
+    IF array_upper( in_requirements, 1 ) IS NOT NULL THEN
+        t_text_a := '{}';
+        FOR i IN array_lower( in_requirements, 1 ) .. array_upper( 
in_requirements, 1 ) LOOP
+            SELECT patch_name INTO t_text FROM _v.patches WHERE patch_name = 
in_requirements[i];
+            IF NOT FOUND THEN
+                t_text_a := t_text_a || in_requirements[i];
+            END IF;
+        END LOOP;
+        IF array_upper( t_text_a, 1 ) IS NOT NULL THEN
+            RAISE EXCEPTION 'Missing prerequisite(s): %.', array_to_string( 
t_text_a, ', ' );
+        END IF;
+    END IF;
+
+    INSERT INTO _v.patches (patch_name, applied_tsz, applied_by, requires, 
conflicts ) VALUES ( in_patch_name, now(), current_user, coalesce( 
in_requirements, '{}' ), coalesce( in_conflicts, '{}' ) );
+    RETURN;
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.register_patch( TEXT, TEXT[], TEXT[]) IS 'Function to 
register patches in database. Raises exception if there are conflicts, 
prerequisites are not installed or the migration has already been installed.';
+
+CREATE OR REPLACE FUNCTION _v.register_patch( TEXT, TEXT[] ) RETURNS setof 
INT4 AS $$
+    SELECT _v.register_patch( $1, $2, NULL );
+$$ language sql;
+COMMENT ON FUNCTION _v.register_patch( TEXT, TEXT[] ) IS 'Wrapper to allow 
registration of patches without conflicts.';
+CREATE OR REPLACE FUNCTION _v.register_patch( TEXT ) RETURNS setof INT4 AS $$
+    SELECT _v.register_patch( $1, NULL, NULL );
+$$ language sql;
+COMMENT ON FUNCTION _v.register_patch( TEXT ) IS 'Wrapper to allow 
registration of patches without requirements and conflicts.';
+
+CREATE OR REPLACE FUNCTION _v.unregister_patch( IN in_patch_name TEXT, OUT 
versioning INT4 ) RETURNS setof INT4 AS $$
+DECLARE
+    i        INT4;
+    t_text_a TEXT[];
+BEGIN
+    -- Thanks to this we know only one patch will be applied at a time
+    LOCK TABLE _v.patches IN EXCLUSIVE MODE;
+
+    t_text_a := ARRAY( SELECT patch_name FROM _v.patches WHERE in_patch_name = 
ANY( requires ) );
+    IF array_upper( t_text_a, 1 ) IS NOT NULL THEN
+        RAISE EXCEPTION 'Cannot uninstall %, as it is required by: %.', 
in_patch_name, array_to_string( t_text_a, ', ' );
+    END IF;
+
+    DELETE FROM _v.patches WHERE patch_name = in_patch_name;
+    GET DIAGNOSTICS i = ROW_COUNT;
+    IF i < 1 THEN
+        RAISE EXCEPTION 'Patch % is not installed, so it can''t be 
uninstalled!', in_patch_name;
+    END IF;
+
+    RETURN;
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.unregister_patch( TEXT ) IS 'Function to unregister 
patches in database. Dies if the patch is not registered, or if unregistering 
it would break dependencies.';
+
+CREATE OR REPLACE FUNCTION _v.assert_patch_is_applied( IN in_patch_name TEXT ) 
RETURNS TEXT as $$
+DECLARE
+    t_text TEXT;
+BEGIN
+    SELECT patch_name INTO t_text FROM _v.patches WHERE patch_name = 
in_patch_name;
+    IF NOT FOUND THEN
+        RAISE EXCEPTION 'Patch % is not applied!', in_patch_name;
+    END IF;
+    RETURN format('Patch %s is applied.', in_patch_name);
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.assert_patch_is_applied( TEXT ) IS 'Function that can 
be used to make sure that patch has been applied.';
+
+CREATE OR REPLACE FUNCTION _v.assert_user_is_superuser() RETURNS TEXT as $$
+DECLARE
+    v_super bool;
+BEGIN
+    SELECT usesuper INTO v_super FROM pg_user WHERE usename = current_user;
+    IF v_super THEN
+        RETURN 'assert_user_is_superuser: OK';
+    END IF;
+    RAISE EXCEPTION 'Current user is not superuser - cannot continue.';
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.assert_user_is_superuser() IS 'Function that can be 
used to make sure that patch is being applied using superuser account.';
+
+CREATE OR REPLACE FUNCTION _v.assert_user_is_not_superuser() RETURNS TEXT as $$
+DECLARE
+    v_super bool;
+BEGIN
+    SELECT usesuper INTO v_super FROM pg_user WHERE usename = current_user;
+    IF v_super THEN
+        RAISE EXCEPTION 'Current user is superuser - cannot continue.';
+    END IF;
+    RETURN 'assert_user_is_not_superuser: OK';
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.assert_user_is_not_superuser() IS 'Function that can be 
used to make sure that patch is being applied using normal (not superuser) 
account.';
+
+CREATE OR REPLACE FUNCTION _v.assert_user_is_one_of(VARIADIC 
p_acceptable_users TEXT[] ) RETURNS TEXT as $$
+DECLARE
+BEGIN
+    IF current_user = any( p_acceptable_users ) THEN
+        RETURN 'assert_user_is_one_of: OK';
+    END IF;
+    RAISE EXCEPTION 'User is not one of: % - cannot continue.', 
p_acceptable_users;
+END;
+$$ language plpgsql;
+COMMENT ON FUNCTION _v.assert_user_is_one_of(TEXT[]) IS 'Function that can be 
used to make sure that patch is being applied by one of defined users.';
+
+COMMIT;
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index 1f16da78..b20ba00f 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -379,7 +379,9 @@ class Serve : CliktCommand("Run sandbox HTTP server") {
             )
             exitProcess(1)
         }
-        execThrowableOrTerminate { 
dbCreateTables(getDbConnFromEnv(SANDBOX_DB_ENV_VAR_NAME)) }
+        execThrowableOrTerminate {
+            dbCreateTables(getDbConnFromEnv(SANDBOX_DB_ENV_VAR_NAME))
+        }
         // Refuse to operate without a 'default' demobank.
         val demobank = getDemobank("default")
         if (demobank == null) {
diff --git a/util/src/main/kotlin/DB.kt b/util/src/main/kotlin/DB.kt
index 90065529..d8ac3fbe 100644
--- a/util/src/main/kotlin/DB.kt
+++ b/util/src/main/kotlin/DB.kt
@@ -25,6 +25,7 @@ import logger
 import net.taler.wallet.crypto.Base32Crockford
 import org.jetbrains.exposed.sql.Transaction
 import org.jetbrains.exposed.sql.transactions.TransactionManager
+import org.jetbrains.exposed.sql.transactions.transaction
 import org.postgresql.jdbc.PgConnection
 
 fun Transaction.isPostgres(): Boolean {
@@ -217,4 +218,15 @@ class PostgresListenHandle(val channelName: String) {
         conn.close()
         return false
     }
+}
+
+fun getDatabaseName(): String {
+    var maybe_db_name: String? = null
+    transaction {
+        this.exec("SELECT current_database() AS database_name;") { oneLineRes 
->
+            if (oneLineRes.next())
+                maybe_db_name = oneLineRes.getString("database_name")
+        }
+    }
+    return maybe_db_name ?: throw internalServerError("Could not find current 
DB name")
 }
\ No newline at end of file
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Errors.kt 
b/util/src/main/kotlin/exec.kt
similarity index 58%
copy from nexus/src/main/kotlin/tech/libeufin/nexus/Errors.kt
copy to util/src/main/kotlin/exec.kt
index 0cc340e8..c29d5b04 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/Errors.kt
+++ b/util/src/main/kotlin/exec.kt
@@ -1,35 +1,33 @@
 /*
  * This file is part of LibEuFin.
- * Copyright (C) 2020 Taler Systems S.A.
- *
+ * 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.nexus
+package tech.libeufin.util
 
-import io.ktor.http.HttpStatusCode
-import tech.libeufin.util.LibeufinErrorCode
-
-data class NexusError(
-    val statusCode: HttpStatusCode,
-    val reason: String,
-    val code: LibeufinErrorCode? = null
-    ) :
-    Exception("$reason (HTTP status $statusCode)")
-
-fun NexusAssert(condition: Boolean, errorMsg: String): Boolean {
-    if (! condition) throw NexusError(HttpStatusCode.InternalServerError, 
errorMsg)
-    return true
+/**
+ * Wrapper around the ProcessBuilder API.  It executes a
+ * command and throws exception if the result is not zero.
+ */
+fun execCommand(cmd: List<String>) {
+    val result: Int = ProcessBuilder(cmd)
+        .redirectOutput(ProcessBuilder.Redirect.INHERIT)
+        .redirectError(ProcessBuilder.Redirect.INHERIT)
+        .start()
+        .waitFor()
+    if (result != 0) throw internalServerError("Command '$cmd' failed.")
 }
\ 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]