summaryrefslogtreecommitdiff
path: root/nexus/src/main/kotlin/tech/libeufin/nexus/server
diff options
context:
space:
mode:
authorms <ms@taler.net>2021-10-06 17:00:24 +0200
committerms <ms@taler.net>2021-10-06 17:00:24 +0200
commit16847b5057f2e229995fdb1e62837c84930ebb62 (patch)
tree1a6799951533ca869495de8da1a85102ca5557da /nexus/src/main/kotlin/tech/libeufin/nexus/server
parent6144c4a6203549a16390356ea8deb9b5b6a464a9 (diff)
downloadlibeufin-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.kt1542
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)