diff options
author | ms <ms@taler.net> | 2021-10-06 17:00:24 +0200 |
---|---|---|
committer | ms <ms@taler.net> | 2021-10-06 17:00:24 +0200 |
commit | 16847b5057f2e229995fdb1e62837c84930ebb62 (patch) | |
tree | 1a6799951533ca869495de8da1a85102ca5557da /nexus/src/main/kotlin/tech/libeufin/nexus/server | |
parent | 6144c4a6203549a16390356ea8deb9b5b6a464a9 (diff) | |
download | libeufin-16847b5057f2e229995fdb1e62837c84930ebb62.tar.gz libeufin-16847b5057f2e229995fdb1e62837c84930ebb62.tar.bz2 libeufin-16847b5057f2e229995fdb1e62837c84930ebb62.zip |
Serve Nexus via Unix domain socket
Diffstat (limited to 'nexus/src/main/kotlin/tech/libeufin/nexus/server')
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt | 1542 |
1 files changed, 771 insertions, 771 deletions
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt index 0b6098ec..5fb37ea4 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt @@ -150,911 +150,911 @@ fun requireBankConnection(call: ApplicationCall, parameterKey: String): NexusBan } val client = HttpClient { followRedirects = true } - -fun serverMain(host: String, port: Int) { - val server = embeddedServer(Netty, port = port, host = host) { - install(CallLogging) { - this.level = Level.DEBUG - this.logger = tech.libeufin.nexus.logger - } - install(ContentNegotiation) { - jackson { - enable(SerializationFeature.INDENT_OUTPUT) - setDefaultPrettyPrinter(DefaultPrettyPrinter().apply { - indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance) - indentObjectsWith(DefaultIndenter(" ", "\n")) - }) - registerModule(KotlinModule(nullisSameAsDefault = true)) - configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - } +val nexusApp: Application.() -> Unit = { + install(CallLogging) { + this.level = Level.DEBUG + this.logger = tech.libeufin.nexus.logger + } + install(ContentNegotiation) { + jackson { + enable(SerializationFeature.INDENT_OUTPUT) + setDefaultPrettyPrinter(DefaultPrettyPrinter().apply { + indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance) + indentObjectsWith(DefaultIndenter(" ", "\n")) + }) + registerModule(KotlinModule(nullisSameAsDefault = true)) + configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) } - install(StatusPages) { - exception<NexusError> { cause -> - logger.error("Caught exception while handling '${call.request.uri} (${cause.reason})") - call.respond( - status = cause.statusCode, - message = ErrorResponse( - code = TalerErrorCode.TALER_EC_LIBEUFIN_NEXUS_GENERIC_ERROR.code, - hint = "nexus error, see detail", - detail = cause.reason, - ) + } + install(StatusPages) { + exception<NexusError> { cause -> + logger.error("Caught exception while handling '${call.request.uri} (${cause.reason})") + call.respond( + status = cause.statusCode, + message = ErrorResponse( + code = TalerErrorCode.TALER_EC_LIBEUFIN_NEXUS_GENERIC_ERROR.code, + hint = "nexus error, see detail", + detail = cause.reason, ) - } - exception<JsonMappingException> { cause -> - logger.error("Exception while handling '${call.request.uri}'", cause) - call.respond( - HttpStatusCode.BadRequest, - message = ErrorResponse( - code = TalerErrorCode.TALER_EC_GENERIC_JSON_INVALID.code, - hint = "POSTed data was not valid", - detail = cause.message ?: "not given", - ) + ) + } + exception<JsonMappingException> { cause -> + logger.error("Exception while handling '${call.request.uri}'", cause) + call.respond( + HttpStatusCode.BadRequest, + message = ErrorResponse( + code = TalerErrorCode.TALER_EC_GENERIC_JSON_INVALID.code, + hint = "POSTed data was not valid", + detail = cause.message ?: "not given", ) - } - exception<UtilError> { cause -> - logger.error("Exception while handling '${call.request.uri}'", cause) - call.respond( - cause.statusCode, - message = ErrorResponse( - code = cause.ec?.code ?: TalerErrorCode.TALER_EC_NONE.code, - hint = "see detail", - detail = cause.reason, - ) + ) + } + exception<UtilError> { cause -> + logger.error("Exception while handling '${call.request.uri}'", cause) + call.respond( + cause.statusCode, + message = ErrorResponse( + code = cause.ec?.code ?: TalerErrorCode.TALER_EC_NONE.code, + hint = "see detail", + detail = cause.reason, ) - } - exception<EbicsProtocolError> { cause -> - logger.error("Caught exception while handling '${call.request.uri}' (${cause.reason})") - call.respond( - cause.httpStatusCode, - message = ErrorResponse( - code = TalerErrorCode.TALER_EC_LIBEUFIN_NEXUS_GENERIC_ERROR.code, - hint = "EBICS protocol error", - detail = cause.reason, - ) + ) + } + exception<EbicsProtocolError> { cause -> + logger.error("Caught exception while handling '${call.request.uri}' (${cause.reason})") + call.respond( + cause.httpStatusCode, + message = ErrorResponse( + code = TalerErrorCode.TALER_EC_LIBEUFIN_NEXUS_GENERIC_ERROR.code, + hint = "EBICS protocol error", + detail = cause.reason, ) - } - exception<Exception> { cause -> - logger.error("Uncaught exception while handling '${call.request.uri}'") - cause.printStackTrace() - call.respond( - HttpStatusCode.InternalServerError, - ErrorResponse( - code = TalerErrorCode.TALER_EC_LIBEUFIN_NEXUS_UNCAUGHT_EXCEPTION.code, - hint = "unexpected exception", - detail = "exception message: ${cause.message}", - ) + ) + } + exception<Exception> { cause -> + logger.error("Uncaught exception while handling '${call.request.uri}'") + cause.printStackTrace() + call.respond( + HttpStatusCode.InternalServerError, + ErrorResponse( + code = TalerErrorCode.TALER_EC_LIBEUFIN_NEXUS_UNCAUGHT_EXCEPTION.code, + hint = "unexpected exception", + detail = "exception message: ${cause.message}", ) - } + ) } - install(RequestBodyDecompression) - intercept(ApplicationCallPipeline.Fallback) { - if (this.call.response.status() == null) { - call.respondText("Not found (no route matched).\n", ContentType.Text.Plain, HttpStatusCode.NotFound) - return@intercept finish() - } + } + install(RequestBodyDecompression) + intercept(ApplicationCallPipeline.Fallback) { + if (this.call.response.status() == null) { + call.respondText("Not found (no route matched).\n", ContentType.Text.Plain, HttpStatusCode.NotFound) + return@intercept finish() } - routing { - get("/config") { - call.respond( - makeJsonObject { - prop("version", getVersion()) - } - ) - return@get - } - // Shows information about the requesting user. - get("/user") { - val ret = transaction { - val currentUser = authenticateRequest(call.request) - UserResponse( - username = currentUser.username, - superuser = currentUser.superuser - ) + } + routing { + get("/config") { + call.respond( + makeJsonObject { + prop("version", getVersion()) } - call.respond(ret) - return@get + ) + return@get + } + // Shows information about the requesting user. + get("/user") { + val ret = transaction { + val currentUser = authenticateRequest(call.request) + UserResponse( + username = currentUser.username, + superuser = currentUser.superuser + ) } + call.respond(ret) + return@get + } - get("/permissions") { - val resp = object { - val permissions = mutableListOf<Permission>() - } - transaction { - requireSuperuser(call.request) - NexusPermissionEntity.all().map { - resp.permissions.add( - Permission( - subjectType = it.subjectType, - subjectId = it.subjectId, - resourceType = it.resourceType, - resourceId = it.resourceId, - permissionName = it.permissionName, - ) + get("/permissions") { + val resp = object { + val permissions = mutableListOf<Permission>() + } + transaction { + requireSuperuser(call.request) + NexusPermissionEntity.all().map { + resp.permissions.add( + Permission( + subjectType = it.subjectType, + subjectId = it.subjectId, + resourceType = it.resourceType, + resourceId = it.resourceId, + permissionName = it.permissionName, ) - } + ) } - call.respond(resp) } + call.respond(resp) + } - post("/permissions") { - val req = call.receive<ChangePermissionsRequest>() - val knownPermissions = listOf( - "facade.talerwiregateway.history", "facade.talerwiregateway.transfer", - "facade.anastasis.history" + post("/permissions") { + val req = call.receive<ChangePermissionsRequest>() + val knownPermissions = listOf( + "facade.talerwiregateway.history", "facade.talerwiregateway.transfer", + "facade.anastasis.history" + ) + val permName = req.permission.permissionName.lowercase() + if (!knownPermissions.contains(permName)) { + throw NexusError( + HttpStatusCode.BadRequest, + "Permission $permName not known" ) - val permName = req.permission.permissionName.lowercase() - if (!knownPermissions.contains(permName)) { - throw NexusError( - HttpStatusCode.BadRequest, - "Permission $permName not known" - ) - } - transaction { - requireSuperuser(call.request) - val existingPerm = findPermission(req.permission) - when (req.action) { - PermissionChangeAction.GRANT -> { - if (existingPerm == null) { - NexusPermissionEntity.new { - subjectType = req.permission.subjectType - subjectId = req.permission.subjectId - resourceType = req.permission.resourceType - resourceId = req.permission.resourceId - permissionName = permName + } + transaction { + requireSuperuser(call.request) + val existingPerm = findPermission(req.permission) + when (req.action) { + PermissionChangeAction.GRANT -> { + if (existingPerm == null) { + NexusPermissionEntity.new { + subjectType = req.permission.subjectType + subjectId = req.permission.subjectId + resourceType = req.permission.resourceType + resourceId = req.permission.resourceId + permissionName = permName - } } } - PermissionChangeAction.REVOKE -> { - existingPerm?.delete() - } } - null - } - call.respond(object {}) - } - - get("/users") { - transaction { - requireSuperuser(call.request) - } - val users = transaction { - transaction { - NexusUserEntity.all().map { - UserInfo(it.username, it.superuser) - } + PermissionChangeAction.REVOKE -> { + existingPerm?.delete() } } - val usersResp = UsersResponse(users) - call.respond(usersResp) - return@get + null } + call.respond(object {}) + } - // change a user's password - post("/users/{username}/password") { - val body = call.receiveJson<ChangeUserPassword>() - val targetUsername = ensureNonNull(call.parameters["username"]) - transaction { - requireSuperuser(call.request) - val targetUser = NexusUserEntity.find { - NexusUsersTable.username eq targetUsername - }.firstOrNull() - if (targetUser == null) throw NexusError( - HttpStatusCode.NotFound, - "Username $targetUsername not found" - ) - targetUser.passwordHash = CryptoUtil.hashpw(body.newPassword) - } - call.respond(NexusMessage(message = "Password successfully changed")) - return@post + get("/users") { + transaction { + requireSuperuser(call.request) } - - // Add a new ordinary user in the system (requires superuser privileges) - post("/users") { - val body = call.receiveJson<CreateUserRequest>() - val requestedUsername = requireValidResourceName(body.username) + val users = transaction { transaction { - requireSuperuser(call.request) - // check if username is available - val checkUsername = NexusUserEntity.find { - NexusUsersTable.username eq requestedUsername - }.firstOrNull() - if (checkUsername != null) throw NexusError( - HttpStatusCode.Conflict, - "Username $requestedUsername unavailable" - ) - NexusUserEntity.new { - username = requestedUsername - passwordHash = CryptoUtil.hashpw(body.password) - superuser = false + NexusUserEntity.all().map { + UserInfo(it.username, it.superuser) } } - call.respond( - NexusMessage( - message = "New user '${body.username}' registered" - ) - ) - return@post } + val usersResp = UsersResponse(users) + call.respond(usersResp) + return@get + } - get("/bank-connection-protocols") { + // change a user's password + post("/users/{username}/password") { + val body = call.receiveJson<ChangeUserPassword>() + val targetUsername = ensureNonNull(call.parameters["username"]) + transaction { requireSuperuser(call.request) - call.respond( - HttpStatusCode.OK, - BankProtocolsResponse(listOf("ebics", "loopback")) + val targetUser = NexusUserEntity.find { + NexusUsersTable.username eq targetUsername + }.firstOrNull() + if (targetUser == null) throw NexusError( + HttpStatusCode.NotFound, + "Username $targetUsername not found" ) - return@get + targetUser.passwordHash = CryptoUtil.hashpw(body.newPassword) } + call.respond(NexusMessage(message = "Password successfully changed")) + return@post + } - route("/bank-connection-protocols/ebics") { - ebicsBankProtocolRoutes(client) + // Add a new ordinary user in the system (requires superuser privileges) + post("/users") { + val body = call.receiveJson<CreateUserRequest>() + val requestedUsername = requireValidResourceName(body.username) + transaction { + requireSuperuser(call.request) + // check if username is available + val checkUsername = NexusUserEntity.find { + NexusUsersTable.username eq requestedUsername + }.firstOrNull() + if (checkUsername != null) throw NexusError( + HttpStatusCode.Conflict, + "Username $requestedUsername unavailable" + ) + NexusUserEntity.new { + username = requestedUsername + passwordHash = CryptoUtil.hashpw(body.password) + superuser = false + } } + call.respond( + NexusMessage( + message = "New user '${body.username}' registered" + ) + ) + return@post + } - // Shows the bank accounts belonging to the requesting user. - get("/bank-accounts") { - val bankAccounts = BankAccounts() - transaction { - authenticateRequest(call.request) - // FIXME(dold): Only return accounts the user has at least read access to? - NexusBankAccountEntity.all().forEach { - bankAccounts.accounts.add( - BankAccount( - ownerName = it.accountHolder, - iban = it.iban, - bic = it.bankCode, - nexusBankAccountId = it.bankAccountName - ) + get("/bank-connection-protocols") { + requireSuperuser(call.request) + call.respond( + HttpStatusCode.OK, + BankProtocolsResponse(listOf("ebics", "loopback")) + ) + return@get + } + + route("/bank-connection-protocols/ebics") { + ebicsBankProtocolRoutes(client) + } + + // Shows the bank accounts belonging to the requesting user. + get("/bank-accounts") { + val bankAccounts = BankAccounts() + transaction { + authenticateRequest(call.request) + // FIXME(dold): Only return accounts the user has at least read access to? + NexusBankAccountEntity.all().forEach { + bankAccounts.accounts.add( + BankAccount( + ownerName = it.accountHolder, + iban = it.iban, + bic = it.bankCode, + nexusBankAccountId = it.bankAccountName ) - } + ) } - call.respond(bankAccounts) - return@get } - post("/bank-accounts/{accountId}/test-camt-ingestion/{type}") { - requireSuperuser(call.request) - processCamtMessage( - ensureNonNull(call.parameters["accountId"]), - XMLUtil.parseStringIntoDom(call.receiveText()), - ensureNonNull(call.parameters["type"]) - ) - call.respond(object {}) - return@post - } - get("/bank-accounts/{accountId}/schedule") { - requireSuperuser(call.request) - val resp = jacksonObjectMapper().createObjectNode() - val ops = jacksonObjectMapper().createObjectNode() - val accountId = ensureNonNull(call.parameters["accountId"]) - resp.set<JsonNode>("schedule", ops) - transaction { - NexusBankAccountEntity.findByName(accountId) - ?: throw NexusError(HttpStatusCode.NotFound, "unknown bank account") - NexusScheduledTaskEntity.find { - (NexusScheduledTasksTable.resourceType eq "bank-account") and - (NexusScheduledTasksTable.resourceId eq accountId) + call.respond(bankAccounts) + return@get + } + post("/bank-accounts/{accountId}/test-camt-ingestion/{type}") { + requireSuperuser(call.request) + processCamtMessage( + ensureNonNull(call.parameters["accountId"]), + XMLUtil.parseStringIntoDom(call.receiveText()), + ensureNonNull(call.parameters["type"]) + ) + call.respond(object {}) + return@post + } + get("/bank-accounts/{accountId}/schedule") { + requireSuperuser(call.request) + val resp = jacksonObjectMapper().createObjectNode() + val ops = jacksonObjectMapper().createObjectNode() + val accountId = ensureNonNull(call.parameters["accountId"]) + resp.set<JsonNode>("schedule", ops) + transaction { + NexusBankAccountEntity.findByName(accountId) + ?: throw NexusError(HttpStatusCode.NotFound, "unknown bank account") + NexusScheduledTaskEntity.find { + (NexusScheduledTasksTable.resourceType eq "bank-account") and + (NexusScheduledTasksTable.resourceId eq accountId) - }.forEach { - val t = jacksonObjectMapper().createObjectNode() - ops.set<JsonNode>(it.taskName, t) - t.put("cronspec", it.taskCronspec) - t.put("type", it.taskType) - t.set<JsonNode>("params", jacksonObjectMapper().readTree(it.taskParams)) - } + }.forEach { + val t = jacksonObjectMapper().createObjectNode() + ops.set<JsonNode>(it.taskName, t) + t.put("cronspec", it.taskCronspec) + t.put("type", it.taskType) + t.set<JsonNode>("params", jacksonObjectMapper().readTree(it.taskParams)) } - call.respond(resp) - return@get } + call.respond(resp) + return@get + } - post("/bank-accounts/{accountId}/schedule") { - requireSuperuser(call.request) - val schedSpec = call.receive<CreateAccountTaskRequest>() - val accountId = ensureNonNull(call.parameters["accountId"]) - transaction { - authenticateRequest(call.request) - NexusBankAccountEntity.findByName(accountId) - ?: throw NexusError(HttpStatusCode.NotFound, "unknown bank account") - try { - NexusCron.parser.parse(schedSpec.cronspec) - } catch (e: IllegalArgumentException) { - throw NexusError(HttpStatusCode.BadRequest, "bad cron spec: ${e.message}") - } - // sanity checks. - when (schedSpec.type) { - "fetch" -> { - jacksonObjectMapper().treeToValue(schedSpec.params, FetchSpecJson::class.java) - ?: throw NexusError(HttpStatusCode.BadRequest, "bad fetch spec") - } - "submit" -> { - } - else -> throw NexusError(HttpStatusCode.BadRequest, "unsupported task type") - } - val oldSchedTask = NexusScheduledTaskEntity.find { - (NexusScheduledTasksTable.taskName eq schedSpec.name) and - (NexusScheduledTasksTable.resourceType eq "bank-account") and - (NexusScheduledTasksTable.resourceId eq accountId) - - }.firstOrNull() - if (oldSchedTask != null) { - throw NexusError(HttpStatusCode.BadRequest, "schedule task already exists") + post("/bank-accounts/{accountId}/schedule") { + requireSuperuser(call.request) + val schedSpec = call.receive<CreateAccountTaskRequest>() + val accountId = ensureNonNull(call.parameters["accountId"]) + transaction { + authenticateRequest(call.request) + NexusBankAccountEntity.findByName(accountId) + ?: throw NexusError(HttpStatusCode.NotFound, "unknown bank account") + try { + NexusCron.parser.parse(schedSpec.cronspec) + } catch (e: IllegalArgumentException) { + throw NexusError(HttpStatusCode.BadRequest, "bad cron spec: ${e.message}") + } + // sanity checks. + when (schedSpec.type) { + "fetch" -> { + jacksonObjectMapper().treeToValue(schedSpec.params, FetchSpecJson::class.java) + ?: throw NexusError(HttpStatusCode.BadRequest, "bad fetch spec") } - NexusScheduledTaskEntity.new { - resourceType = "bank-account" - resourceId = accountId - this.taskCronspec = schedSpec.cronspec - this.taskName = requireValidResourceName(schedSpec.name) - this.taskType = schedSpec.type - this.taskParams = - jacksonObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(schedSpec.params) + "submit" -> { } + else -> throw NexusError(HttpStatusCode.BadRequest, "unsupported task type") } - call.respond(object {}) - return@post - } + val oldSchedTask = NexusScheduledTaskEntity.find { + (NexusScheduledTasksTable.taskName eq schedSpec.name) and + (NexusScheduledTasksTable.resourceType eq "bank-account") and + (NexusScheduledTasksTable.resourceId eq accountId) - get("/bank-accounts/{accountId}/schedule/{taskId}") { - requireSuperuser(call.request) - val taskId = ensureNonNull(call.parameters["taskId"]) - val task = transaction { - NexusScheduledTaskEntity.find { - NexusScheduledTasksTable.taskName eq taskId - }.firstOrNull() + }.firstOrNull() + if (oldSchedTask != null) { + throw NexusError(HttpStatusCode.BadRequest, "schedule task already exists") + } + NexusScheduledTaskEntity.new { + resourceType = "bank-account" + resourceId = accountId + this.taskCronspec = schedSpec.cronspec + this.taskName = requireValidResourceName(schedSpec.name) + this.taskType = schedSpec.type + this.taskParams = + jacksonObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(schedSpec.params) } - if (task == null) throw NexusError(HttpStatusCode.NotFound, "Task ${taskId} wasn't found") - call.respond( - AccountTask( - resourceId = task.resourceId, - resourceType = task.resourceType, - taskName = task.taskName, - taskCronspec = task.taskCronspec, - taskType = task.taskType, - taskParams = task.taskParams, - nextScheduledExecutionSec = task.nextScheduledExecutionSec, - prevScheduledExecutionSec = task.prevScheduledExecutionSec - ) - ) - return@get } + call.respond(object {}) + return@post + } - delete("/bank-accounts/{accountId}/schedule/{taskId}") { - requireSuperuser(call.request) - logger.info("schedule delete requested") - val accountId = ensureNonNull(call.parameters["accountId"]) - val taskId = ensureNonNull(call.parameters["taskId"]) - transaction { - val bankAccount = NexusBankAccountEntity.findByName(accountId) - if (bankAccount == null) { - throw NexusError(HttpStatusCode.NotFound, "unknown bank account") - } - val oldSchedTask = NexusScheduledTaskEntity.find { - (NexusScheduledTasksTable.taskName eq taskId) and - (NexusScheduledTasksTable.resourceType eq "bank-account") and - (NexusScheduledTasksTable.resourceId eq accountId) + get("/bank-accounts/{accountId}/schedule/{taskId}") { + requireSuperuser(call.request) + val taskId = ensureNonNull(call.parameters["taskId"]) + val task = transaction { + NexusScheduledTaskEntity.find { + NexusScheduledTasksTable.taskName eq taskId + }.firstOrNull() + } + if (task == null) throw NexusError(HttpStatusCode.NotFound, "Task ${taskId} wasn't found") + call.respond( + AccountTask( + resourceId = task.resourceId, + resourceType = task.resourceType, + taskName = task.taskName, + taskCronspec = task.taskCronspec, + taskType = task.taskType, + taskParams = task.taskParams, + nextScheduledExecutionSec = task.nextScheduledExecutionSec, + prevScheduledExecutionSec = task.prevScheduledExecutionSec + ) + ) + return@get + } - }.firstOrNull() - oldSchedTask?.delete() + delete("/bank-accounts/{accountId}/schedule/{taskId}") { + requireSuperuser(call.request) + logger.info("schedule delete requested") + val accountId = ensureNonNull(call.parameters["accountId"]) + val taskId = ensureNonNull(call.parameters["taskId"]) + transaction { + val bankAccount = NexusBankAccountEntity.findByName(accountId) + if (bankAccount == null) { + throw NexusError(HttpStatusCode.NotFound, "unknown bank account") } - call.respond(object {}) + val oldSchedTask = NexusScheduledTaskEntity.find { + (NexusScheduledTasksTable.taskName eq taskId) and + (NexusScheduledTasksTable.resourceType eq "bank-account") and + (NexusScheduledTasksTable.resourceId eq accountId) + + }.firstOrNull() + oldSchedTask?.delete() } + call.respond(object {}) + } - get("/bank-accounts/{accountid}") { - requireSuperuser(call.request) - val accountId = ensureNonNull(call.parameters["accountid"]) - val res = transaction { - val bankAccount = NexusBankAccountEntity.findByName(accountId) - if (bankAccount == null) { - throw NexusError(HttpStatusCode.NotFound, "unknown bank account") - } - val holderEnc = URLEncoder.encode(bankAccount.accountHolder, "UTF-8") - val lastSeenBalance = NexusBankBalanceEntity.find { - NexusBankBalancesTable.bankAccount eq bankAccount.id - }.lastOrNull() - return@transaction makeJsonObject { - prop("defaultBankConnection", bankAccount.defaultBankConnection?.id?.value) - prop("accountPaytoUri", "payto://iban/${bankAccount.iban}?receiver-name=$holderEnc") - prop( - "lastSeenBalance", - if (lastSeenBalance != null) { - val sign = if (lastSeenBalance.creditDebitIndicator == "DBIT") "-" else "" - "${sign}${lastSeenBalance.balance}" - } else { - "not downloaded from the bank yet" - } - ) - } + get("/bank-accounts/{accountid}") { + requireSuperuser(call.request) + val accountId = ensureNonNull(call.parameters["accountid"]) + val res = transaction { + val bankAccount = NexusBankAccountEntity.findByName(accountId) + if (bankAccount == null) { + throw NexusError(HttpStatusCode.NotFound, "unknown bank account") + } + val holderEnc = URLEncoder.encode(bankAccount.accountHolder, "UTF-8") + val lastSeenBalance = NexusBankBalanceEntity.find { + NexusBankBalancesTable.bankAccount eq bankAccount.id + }.lastOrNull() + return@transaction makeJsonObject { + prop("defaultBankConnection", bankAccount.defaultBankConnection?.id?.value) + prop("accountPaytoUri", "payto://iban/${bankAccount.iban}?receiver-name=$holderEnc") + prop( + "lastSeenBalance", + if (lastSeenBalance != null) { + val sign = if (lastSeenBalance.creditDebitIndicator == "DBIT") "-" else "" + "${sign}${lastSeenBalance.balance}" + } else { + "not downloaded from the bank yet" + } + ) } - call.respond(res) } + call.respond(res) + } - // Submit one particular payment to the bank. - post("/bank-accounts/{accountid}/payment-initiations/{uuid}/submit") { - requireSuperuser(call.request) - val uuid = ensureLong(call.parameters["uuid"]) - transaction { - authenticateRequest(call.request) - } - submitPaymentInitiation(client, uuid) - call.respondText("Payment $uuid submitted") - return@post + // Submit one particular payment to the bank. + post("/bank-accounts/{accountid}/payment-initiations/{uuid}/submit") { + requireSuperuser(call.request) + val uuid = ensureLong(call.parameters["uuid"]) + transaction { + authenticateRequest(call.request) } + submitPaymentInitiation(client, uuid) + call.respondText("Payment $uuid submitted") + return@post + } - post("/bank-accounts/{accountid}/submit-all-payment-initiations") { - requireSuperuser(call.request) - val accountId = ensureNonNull(call.parameters["accountid"]) - transaction { - authenticateRequest(call.request) - } - submitAllPaymentInitiations(client, accountId) - call.respond(object {}) - return@post + post("/bank-accounts/{accountid}/submit-all-payment-initiations") { + requireSuperuser(call.request) + val accountId = ensureNonNull(call.parameters["accountid"]) + transaction { + authenticateRequest(call.request) } + submitAllPaymentInitiations(client, accountId) + call.respond(object {}) + return@post + } - get("/bank-accounts/{accountid}/payment-initiations") { - requireSuperuser(call.request) - val ret = InitiatedPayments() - transaction { - val bankAccount = requireBankAccount(call, "accountid") - PaymentInitiationEntity.find { - PaymentInitiationsTable.bankAccount eq bankAccount.id.value - }.forEach { - val sd = it.submissionDate - ret.initiatedPayments.add( - PaymentStatus( - status = it.confirmationTransaction?.status, - paymentInitiationId = it.id.value.toString(), - submitted = it.submitted, - creditorIban = it.creditorIban, - creditorName = it.creditorName, - creditorBic = it.creditorBic, - amount = "${it.currency}:${it.sum}", - subject = it.subject, - submissionDate = if (sd != null) { - importDateFromMillis(sd).toDashedDate() - } else null, - preparationDate = importDateFromMillis(it.preparationDate).toDashedDate() - ) + get("/bank-accounts/{accountid}/payment-initiations") { + requireSuperuser(call.request) + val ret = InitiatedPayments() + transaction { + val bankAccount = requireBankAccount(call, "accountid") + PaymentInitiationEntity.find { + PaymentInitiationsTable.bankAccount eq bankAccount.id.value + }.forEach { + val sd = it.submissionDate + ret.initiatedPayments.add( + PaymentStatus( + status = it.confirmationTransaction?.status, + paymentInitiationId = it.id.value.toString(), + submitted = it.submitted, + creditorIban = it.creditorIban, + creditorName = it.creditorName, + creditorBic = it.creditorBic, + amount = "${it.currency}:${it.sum}", + subject = it.subject, + submissionDate = if (sd != null) { + importDateFromMillis(sd).toDashedDate() + } else null, + preparationDate = importDateFromMillis(it.preparationDate).toDashedDate() ) - } + ) } - call.respond(ret) - return@get } + call.respond(ret) + return@get + } - // Shows information about one particular payment initiation. - get("/bank-accounts/{accountid}/payment-initiations/{uuid}") { - requireSuperuser(call.request) - val res = transaction { - val paymentInitiation = getPaymentInitiation(ensureLong(call.parameters["uuid"])) - return@transaction object { - val paymentInitiation = paymentInitiation - val paymentStatus = paymentInitiation.confirmationTransaction?.status - } + // Shows information about one particular payment initiation. + get("/bank-accounts/{accountid}/payment-initiations/{uuid}") { + requireSuperuser(call.request) + val res = transaction { + val paymentInitiation = getPaymentInitiation(ensureLong(call.parameters["uuid"])) + return@transaction object { + val paymentInitiation = paymentInitiation + val paymentStatus = paymentInitiation.confirmationTransaction?.status } - val sd = res.paymentInitiation.submissionDate - call.respond( - PaymentStatus( - paymentInitiationId = res.paymentInitiation.id.value.toString(), - submitted = res.paymentInitiation.submitted, - creditorName = res.paymentInitiation.creditorName, - creditorBic = res.paymentInitiation.creditorBic, - creditorIban = res.paymentInitiation.creditorIban, - amount = "${res.paymentInitiation.currency}:${res.paymentInitiation.sum}", - subject = res.paymentInitiation.subject, - submissionDate = if (sd != null) { - importDateFromMillis(sd).toDashedDate() - } else null, - status = res.paymentStatus, - preparationDate = importDateFromMillis(res.paymentInitiation.preparationDate).toDashedDate() - ) - ) - return@get } + val sd = res.paymentInitiation.submissionDate + call.respond( + PaymentStatus( + paymentInitiationId = res.paymentInitiation.id.value.toString(), + submitted = res.paymentInitiation.submitted, + creditorName = res.paymentInitiation.creditorName, + creditorBic = res.paymentInitiation.creditorBic, + creditorIban = res.paymentInitiation.creditorIban, + amount = "${res.paymentInitiation.currency}:${res.paymentInitiation.sum}", + subject = res.paymentInitiation.subject, + submissionDate = if (sd != null) { + importDateFromMillis(sd).toDashedDate() + } else null, + status = res.paymentStatus, + preparationDate = importDateFromMillis(res.paymentInitiation.preparationDate).toDashedDate() + ) + ) + return@get + } - delete("/bank-accounts/{accountId}/payment-initiations/{uuid}") { - requireSuperuser(call.request) - val uuid = ensureLong(call.parameters["uuid"]) - transaction { - val paymentInitiation = getPaymentInitiation(uuid) - paymentInitiation.delete() - } - call.respond(NexusMessage(message = "Payment initiation $uuid deleted")) + delete("/bank-accounts/{accountId}/payment-initiations/{uuid}") { + requireSuperuser(call.request) + val uuid = ensureLong(call.parameters["uuid"]) + transaction { + val paymentInitiation = getPaymentInitiation(uuid) + paymentInitiation.delete() } + call.respond(NexusMessage(message = "Payment initiation $uuid deleted")) + } - // Adds a new payment initiation. - post("/bank-accounts/{accountid}/payment-initiations") { - requireSuperuser(call.request) - val body = call.receive<CreatePaymentInitiationRequest>() - val accountId = ensureNonNull(call.parameters["accountid"]) - if (!validateBic(body.bic)) { - throw NexusError(HttpStatusCode.BadRequest, "invalid BIC (${body.bic})") + // Adds a new payment initiation. + post("/bank-accounts/{accountid}/payment-initiations") { + requireSuperuser(call.request) + val body = call.receive<CreatePaymentInitiationRequest>() + val accountId = ensureNonNull(call.parameters["accountid"]) + if (!validateBic(body.bic)) { + throw NexusError(HttpStatusCode.BadRequest, "invalid BIC (${body.bic})") + } + val res = transaction { + authenticateRequest(call.request) + val bankAccount = NexusBankAccountEntity.findByName(accountId) + if (bankAccount == null) { + throw NexusError(HttpStatusCode.NotFound, "unknown bank account ($accountId)") } - val res = transaction { - authenticateRequest(call.request) - val bankAccount = NexusBankAccountEntity.findByName(accountId) - if (bankAccount == null) { - throw NexusError(HttpStatusCode.NotFound, "unknown bank account ($accountId)") - } - val amount = parseAmount(body.amount) - val paymentEntity = addPaymentInitiation( - Pain001Data( - creditorIban = body.iban, - creditorBic = body.bic, - creditorName = body.name, - sum = amount.amount, - currency = amount.currency, - subject = body.subject - ), - bankAccount - ) - return@transaction object { - val uuid = paymentEntity.id.value - } + val amount = parseAmount(body.amount) + val paymentEntity = addPaymentInitiation( + Pain001Data( + creditorIban = body.iban, + creditorBic = body.bic, + creditorName = body.name, + sum = amount.amount, + currency = amount.currency, + subject = body.subject + ), + bankAccount + ) + return@transaction object { + val uuid = paymentEntity.id.value } - call.respond( - HttpStatusCode.OK, - PaymentInitiationResponse(uuid = res.uuid.toString()) + } + call.respond( + HttpStatusCode.OK, + PaymentInitiationResponse(uuid = res.uuid.toString()) + ) + return@post + } + + // Downloads new transactions from the bank. + post("/bank-accounts/{accountid}/fetch-transactions") { + requireSuperuser(call.request) + val accountid = call.parameters["accountid"] + if (accountid == null) { + throw NexusError( + HttpStatusCode.BadRequest, + "Account id missing" ) - return@post } + val fetchSpec = if (call.request.hasBody()) { + call.receive<FetchSpecJson>() + } else { + FetchSpecLatestJson( + FetchLevel.STATEMENT, + null + ) + } + val ingestionResult = fetchBankAccountTransactions(client, fetchSpec, accountid) + call.respond(ingestionResult) + return@post + } - // Downloads new transactions from the bank. - post("/bank-accounts/{accountid}/fetch-transactions") { - requireSuperuser(call.request) - val accountid = call.parameters["accountid"] - if (accountid == null) { - throw NexusError( - HttpStatusCode.BadRequest, - "Account id missing" - ) + // Asks list of transactions ALREADY downloaded from the bank. + get("/bank-accounts/{accountid}/transactions") { + requireSuperuser(call.request) + val bankAccountId = expectNonNull(call.parameters["accountid"]) + val ret = Transactions() + transaction { + authenticateRequest(call.request) + val bankAccount = NexusBankAccountEntity.findByName(bankAccountId) + if (bankAccount == null) { + throw NexusError(HttpStatusCode.NotFound, "unknown bank account") } - val fetchSpec = if (call.request.hasBody()) { - call.receive<FetchSpecJson>() - } else { - FetchSpecLatestJson( - FetchLevel.STATEMENT, - null + NexusBankTransactionEntity.find { NexusBankTransactionsTable.bankAccount eq bankAccount.id }.map { + val tx = jacksonObjectMapper().readValue( + it.transactionJson, CamtBankAccountEntry::class.java ) + ret.transactions.add(tx) } - val ingestionResult = fetchBankAccountTransactions(client, fetchSpec, accountid) - call.respond(ingestionResult) - return@post } + call.respond(ret) + return@get + } - // Asks list of transactions ALREADY downloaded from the bank. - get("/bank-accounts/{accountid}/transactions") { - requireSuperuser(call.request) - val bankAccountId = expectNonNull(call.parameters["accountid"]) - val ret = Transactions() - transaction { - authenticateRequest(call.request) - val bankAccount = NexusBankAccountEntity.findByName(bankAccountId) - if (bankAccount == null) { - throw NexusError(HttpStatusCode.NotFound, "unknown bank account") - } - NexusBankTransactionEntity.find { NexusBankTransactionsTable.bankAccount eq bankAccount.id }.map { - val tx = jacksonObjectMapper().readValue( - it.transactionJson, CamtBankAccountEntry::class.java - ) - ret.transactions.add(tx) - } + // Adds a new bank transport. + post("/bank-connections") { + requireSuperuser(call.request) + // user exists and is authenticated. + val body = call.receive<CreateBankConnectionRequestJson>() + requireValidResourceName(body.name) + transaction { + val user = authenticateRequest(call.request) + val existingConn = + NexusBankConnectionEntity.find { NexusBankConnectionsTable.connectionId eq body.name } + .firstOrNull() + if (existingConn != null) { + throw NexusError(HttpStatusCode.Conflict, "connection '${body.name}' exists already") } - call.respond(ret) - return@get - } - - // Adds a new bank transport. - post("/bank-connections") { - requireSuperuser(call.request) - // user exists and is authenticated. - val body = call.receive<CreateBankConnectionRequestJson>() - requireValidResourceName(body.name) - transaction { - val user = authenticateRequest(call.request) - val existingConn = - NexusBankConnectionEntity.find { NexusBankConnectionsTable.connectionId eq body.name } - .firstOrNull() - if (existingConn != null) { - throw NexusError(HttpStatusCode.Conflict, "connection '${body.name}' exists already") - } - when (body) { - is CreateBankConnectionFromBackupRequestJson -> { - val type = body.data.get("type") - if (type == null || !type.isTextual) { - throw NexusError(HttpStatusCode.BadRequest, "backup needs type") - } - val plugin = getConnectionPlugin(type.textValue()) - plugin.createConnectionFromBackup(body.name, user, body.passphrase, body.data) - } - is CreateBankConnectionFromNewRequestJson -> { - val plugin = getConnectionPlugin(body.type) - plugin.createConnection(body.name, user, body.data) + when (body) { + is CreateBankConnectionFromBackupRequestJson -> { + val type = body.data.get("type") + if (type == null || !type.isTextual) { + throw NexusError(HttpStatusCode.BadRequest, "backup needs type") } + val plugin = getConnectionPlugin(type.textValue()) + plugin.createConnectionFromBackup(body.name, user, body.passphrase, body.data) + } + is CreateBankConnectionFromNewRequestJson -> { + val plugin = getConnectionPlugin(body.type) + plugin.createConnection(body.name, user, body.data) } } - call.respond(object {}) } + call.respond(object {}) + } - post("/bank-connections/delete-connection") { - requireSuperuser(call.request) - val body = call.receive<BankConnectionDeletion>() - transaction { - val conn = - NexusBankConnectionEntity.find { NexusBankConnectionsTable.connectionId eq body.bankConnectionId } - .firstOrNull() ?: throw NexusError( - HttpStatusCode.NotFound, - "Bank connection ${body.bankConnectionId}" - ) - conn.delete() // temporary, and instead just _mark_ it as deleted? - } - call.respond(object {}) + post("/bank-connections/delete-connection") { + requireSuperuser(call.request) + val body = call.receive<BankConnectionDeletion>() + transaction { + val conn = + NexusBankConnectionEntity.find { NexusBankConnectionsTable.connectionId eq body.bankConnectionId } + .firstOrNull() ?: throw NexusError( + HttpStatusCode.NotFound, + "Bank connection ${body.bankConnectionId}" + ) + conn.delete() // temporary, and instead just _mark_ it as deleted? } + call.respond(object {}) + } - get("/bank-connections") { - requireSuperuser(call.request) - val connList = BankConnectionsList() - transaction { - NexusBankConnectionEntity.all().forEach { - connList.bankConnections.add( - BankConnectionInfo( - name = it.connectionId, - type = it.type - ) + get("/bank-connections") { + requireSuperuser(call.request) + val connList = BankConnectionsList() + transaction { + NexusBankConnectionEntity.all().forEach { + connList.bankConnections.add( + BankConnectionInfo( + name = it.connectionId, + type = it.type ) - } + ) } - call.respond(connList) } + call.respond(connList) + } - get("/bank-connections/{connectionName}") { - requireSuperuser(call.request) - val resp = transaction { - val conn = requireBankConnection(call, "connectionName") - getConnectionPlugin(conn.type).getConnectionDetails(conn) - } - call.respond(resp) + get("/bank-connections/{connectionName}") { + requireSuperuser(call.request) + val resp = transaction { + val conn = requireBankConnection(call, "connectionName") + getConnectionPlugin(conn.type).getConnectionDetails(conn) } + call.respond(resp) + } - post("/bank-connections/{connectionName}/export-backup") { - requireSuperuser(call.request) - transaction { authenticateRequest(call.request) } - val body = call.receive<BackupRequestJson>() - val response = run { - val conn = requireBankConnection(call, "connectionName") - getConnectionPlugin(conn.type).exportBackup(conn.connectionId, body.passphrase) - } - call.response.headers.append("Content-Disposition", "attachment") - call.respond( - HttpStatusCode.OK, - response - ) + post("/bank-connections/{connectionName}/export-backup") { + requireSuperuser(call.request) + transaction { authenticateRequest(call.request) } + val body = call.receive<BackupRequestJson>() + val response = run { + val conn = requireBankConnection(call, "connectionName") + getConnectionPlugin(conn.type).exportBackup(conn.connectionId, body.passphrase) } + call.response.headers.append("Content-Disposition", "attachment") + call.respond( + HttpStatusCode.OK, + response + ) + } - post("/bank-connections/{connectionName}/connect") { - requireSuperuser(call.request) - val conn = transaction { - authenticateRequest(call.request) - requireBankConnection(call, "connectionName") - } - val plugin = getConnectionPlugin(conn.type) - plugin.connect(client, conn.connectionId) - call.respond(NexusMessage(message = "Connection successful")) + post("/bank-connections/{connectionName}/connect") { + requireSuperuser(call.request) + val conn = transaction { + authenticateRequest(call.request) + requireBankConnection(call, "connectionName") } + val plugin = getConnectionPlugin(conn.type) + plugin.connect(client, conn.connectionId) + call.respond(NexusMessage(message = "Connection successful")) + } - get("/bank-connections/{connectionName}/keyletter") { - requireSuperuser(call.request) - val conn = transaction { - authenticateRequest(call.request) - requireBankConnection(call, "connectionName") - } - val pdfBytes = getConnectionPlugin(conn.type).exportAnalogDetails(conn) - call.respondBytes(pdfBytes, ContentType("application", "pdf")) + get("/bank-connections/{connectionName}/keyletter") { + requireSuperuser(call.request) + val conn = transaction { + authenticateRequest(call.request) + requireBankConnection(call, "connectionName") } + val pdfBytes = getConnectionPlugin(conn.type).exportAnalogDetails(conn) + call.respondBytes(pdfBytes, ContentType("application", "pdf")) + } - get("/bank-connections/{connectionName}/messages") { - requireSuperuser(call.request) - val ret = transaction { - val list = BankMessageList() - val conn = requireBankConnection(call, "connectionName") - NexusBankMessageEntity.find { NexusBankMessagesTable.bankConnection eq conn.id }.map { - list.bankMessages.add( - BankMessageInfo( - it.messageId, - it.code, - it.message.bytes.size.toLong() - ) + get("/bank-connections/{connectionName}/messages") { + requireSuperuser(call.request) + val ret = transaction { + val list = BankMessageList() + val conn = requireBankConnection(call, "connectionName") + NexusBankMessageEntity.find { NexusBankMessagesTable.bankConnection eq conn.id }.map { + list.bankMessages.add( + BankMessageInfo( + it.messageId, + it.code, + it.message.bytes.size.toLong() ) - } - list + ) } - call.respond(ret) + list } + call.respond(ret) + } - get("/bank-connections/{connid}/messages/{msgid}") { - requireSuperuser(call.request) - val ret = transaction { - val msgid = call.parameters["msgid"] - if (msgid == null || msgid == "") { - throw NexusError(HttpStatusCode.BadRequest, "missing or invalid message ID") - } - val msg = NexusBankMessageEntity.find { NexusBankMessagesTable.messageId eq msgid }.firstOrNull() - ?: throw NexusError(HttpStatusCode.NotFound, "bank message not found") - return@transaction object { - val msgContent = msg.message.bytes - } + get("/bank-connections/{connid}/messages/{msgid}") { + requireSuperuser(call.request) + val ret = transaction { + val msgid = call.parameters["msgid"] + if (msgid == null || msgid == "") { + throw NexusError(HttpStatusCode.BadRequest, "missing or invalid message ID") + } + val msg = NexusBankMessageEntity.find { NexusBankMessagesTable.messageId eq msgid }.firstOrNull() + ?: throw NexusError(HttpStatusCode.NotFound, "bank message not found") + return@transaction object { + val msgContent = msg.message.bytes } - call.respondBytes(ret.msgContent, ContentType("application", "xml")) } + call.respondBytes(ret.msgContent, ContentType("application", "xml")) + } - get("/facades/{fcid}") { - requireSuperuser(call.request) - val fcid = ensureNonNull(call.parameters["fcid"]) - val ret = transaction { - val f = FacadeEntity.findByName(fcid) ?: throw NexusError( - HttpStatusCode.NotFound, "Facade $fcid does not exist" - ) - // FIXME: this only works for TWG urls. - FacadeShowInfo( - name = f.facadeName, - type = f.type, - baseUrl = call.url { - parameters.clear() - encodedPath = "" - pathComponents("facades", f.facadeName, f.type) - encodedPath += "/" - }, - config = getFacadeState(f.type, f) - ) - } - call.respond(ret) - return@get + get("/facades/{fcid}") { + requireSuperuser(call.request) + val fcid = ensureNonNull(call.parameters["fcid"]) + val ret = transaction { + val f = FacadeEntity.findByName(fcid) ?: throw NexusError( + HttpStatusCode.NotFound, "Facade $fcid does not exist" + ) + // FIXME: this only works for TWG urls. + FacadeShowInfo( + name = f.facadeName, + type = f.type, + baseUrl = call.url { + parameters.clear() + encodedPath = "" + pathComponents("facades", f.facadeName, f.type) + encodedPath += "/" + }, + config = getFacadeState(f.type, f) + ) } + call.respond(ret) + return@get + } - get("/facades") { - requireSuperuser(call.request) - val ret = object { - val facades = mutableListOf<FacadeShowInfo>() - } - transaction { - val user = authenticateRequest(call.request) - FacadeEntity.find { - FacadesTable.creator eq user.id - }.forEach { - ret.facades.add( - FacadeShowInfo( - name = it.facadeName, - type = it.type, - baseUrl = call.url { - parameters.clear() - encodedPath = "" - pathComponents("facades", it.facadeName, it.type) - encodedPath += "/" - }, - config = getFacadeState(it.type, it) - ) + get("/facades") { + requireSuperuser(call.request) + val ret = object { + val facades = mutableListOf<FacadeShowInfo>() + } + transaction { + val user = authenticateRequest(call.request) + FacadeEntity.find { + FacadesTable.creator eq user.id + }.forEach { + ret.facades.add( + FacadeShowInfo( + name = it.facadeName, + type = it.type, + baseUrl = call.url { + parameters.clear() + encodedPath = "" + pathComponents("facades", it.facadeName, it.type) + encodedPath += "/" + }, + config = getFacadeState(it.type, it) ) - } + ) } - call.respond(ret) - return@get } + call.respond(ret) + return@get + } - delete("/facades/{fcid}") { - requireSuperuser(call.request) - val fcid = ensureNonNull(call.parameters["fcid"]) - transaction { - val f = FacadeEntity.findByName(fcid) ?: throw NexusError( - HttpStatusCode.NotFound, "Facade $fcid does not exist" - ) - f.delete() - } - call.respond({}) - return@delete + delete("/facades/{fcid}") { + requireSuperuser(call.request) + val fcid = ensureNonNull(call.parameters["fcid"]) + transaction { + val f = FacadeEntity.findByName(fcid) ?: throw NexusError( + HttpStatusCode.NotFound, "Facade $fcid does not exist" + ) + f.delete() } + call.respond({}) + return@delete + } - post("/facades") { - requireSuperuser(call.request) - val body = call.receive<FacadeInfo>() - requireValidResourceName(body.name) - if (!listOf("taler-wire-gateway", "anastasis").contains(body.type)) - throw NexusError( + post("/facades") { + requireSuperuser(call.request) + val body = call.receive<FacadeInfo>() + requireValidResourceName(body.name) + if (!listOf("taler-wire-gateway", "anastasis").contains(body.type)) + throw NexusError( HttpStatusCode.NotImplemented, "Facade type '${body.type}' is not implemented" ) - val newFacade = try { - transaction { - val user = authenticateRequest(call.request) - FacadeEntity.new { - facadeName = body.name - type = body.type - creator = user - } - } - } catch (e: ExposedSQLException) { - logger.error("Could not persist facade name/type/creator: $e") - throw NexusError( - HttpStatusCode.BadRequest, - "Server could not persist data, possibly due to unavailable facade name" - ) - } + val newFacade = try { transaction { - FacadeStateEntity.new { - bankAccount = body.config.bankAccount - bankConnection = body.config.bankConnection - reserveTransferLevel = body.config.reserveTransferLevel - facade = newFacade - currency = body.config.currency + val user = authenticateRequest(call.request) + FacadeEntity.new { + facadeName = body.name + type = body.type + creator = user } } - call.respondText("Facade created") - return@post + } catch (e: ExposedSQLException) { + logger.error("Could not persist facade name/type/creator: $e") + throw NexusError( + HttpStatusCode.BadRequest, + "Server could not persist data, possibly due to unavailable facade name" + ) } + transaction { + FacadeStateEntity.new { + bankAccount = body.config.bankAccount + bankConnection = body.config.bankConnection + reserveTransferLevel = body.config.reserveTransferLevel + facade = newFacade + currency = body.config.currency + } + } + call.respondText("Facade created") + return@post + } - route("/bank-connections/{connid}") { + route("/bank-connections/{connid}") { - // only ebics specific tasks under this part. - route("/ebics") { - ebicsBankConnectionRoutes(client) - } - post("/fetch-accounts") { - requireSuperuser(call.request) - val conn = transaction { - authenticateRequest(call.request) - requireBankConnection(call, "connid") - } - getConnectionPlugin(conn.type).fetchAccounts(client, conn.connectionId) - call.respond(object {}) + // only ebics specific tasks under this part. + route("/ebics") { + ebicsBankConnectionRoutes(client) + } + post("/fetch-accounts") { + requireSuperuser(call.request) + val conn = transaction { + authenticateRequest(call.request) + requireBankConnection(call, "connid") } + getConnectionPlugin(conn.type).fetchAccounts(client, conn.connectionId) + call.respond(object {}) + } - // show all the offered accounts (both imported and non) - get("/accounts") { - requireSuperuser(call.request) - val ret = OfferedBankAccounts() - transaction { - val conn = requireBankConnection(call, "connid") - OfferedBankAccountEntity.find { - OfferedBankAccountsTable.bankConnection eq conn.id.value - }.forEach { offeredAccount -> - val importedId = offeredAccount.imported?.id - val imported = if (importedId != null) { - NexusBankAccountEntity.findById(importedId) - } else { - null - } - ret.accounts.add( - OfferedBankAccount( - ownerName = offeredAccount.accountHolder, - iban = offeredAccount.iban, - bic = offeredAccount.bankCode, - offeredAccountId = offeredAccount.offeredAccountId, - nexusBankAccountId = imported?.bankAccountName - ) - ) + // show all the offered accounts (both imported and non) + get("/accounts") { + requireSuperuser(call.request) + val ret = OfferedBankAccounts() + transaction { + val conn = requireBankConnection(call, "connid") + OfferedBankAccountEntity.find { + OfferedBankAccountsTable.bankConnection eq conn.id.value + }.forEach { offeredAccount -> + val importedId = offeredAccount.imported?.id + val imported = if (importedId != null) { + NexusBankAccountEntity.findById(importedId) + } else { + null } + ret.accounts.add( + OfferedBankAccount( + ownerName = offeredAccount.accountHolder, + iban = offeredAccount.iban, + bic = offeredAccount.bankCode, + offeredAccountId = offeredAccount.offeredAccountId, + nexusBankAccountId = imported?.bankAccountName + ) + ) } - call.respond(ret) } - - // import one account into libeufin. - post("/import-account") { - requireSuperuser(call.request) - val body = call.receive<ImportBankAccount>() - importBankAccount(call, body.offeredAccountId, body.nexusBankAccountId) - call.respond(object {}) - } - } - route("/facades/{fcid}/taler-wire-gateway") { - talerFacadeRoutes(this) - } - route("/facades/{fcid}/anastasis") { - anastasisFacadeRoutes(this, client) + call.respond(ret) } - // Hello endpoint. - get("/") { - call.respondText("Hello, this is Nexus.\n") - return@get + // import one account into libeufin. + post("/import-account") { + requireSuperuser(call.request) + val body = call.receive<ImportBankAccount>() + importBankAccount(call, body.offeredAccountId, body.nexusBankAccountId) + call.respond(object {}) } } + route("/facades/{fcid}/taler-wire-gateway") { + talerFacadeRoutes(this) + } + route("/facades/{fcid}/anastasis") { + anastasisFacadeRoutes(this, client) + } + + // Hello endpoint. + get("/") { + call.respondText("Hello, this is Nexus.\n") + return@get + } } +} +fun serverMain(host: String, port: Int) { + val server = embeddedServer(Netty, port = port, host = host, module = nexusApp) logger.info("LibEuFin Nexus running on port $port") try { server.start(wait = true) |