Unverified Commit 843005db authored by seykron's avatar seykron

Adds documentation and makes optional some config parameters

parent 6388e1b1
......@@ -90,3 +90,53 @@ selected and it goes to the next phase.
in order to either reply or ask for user input. We'll discuss the user input in the next
sections.
### Application startup
Standalone applications must extends the [SpringApplication](https://git.rlab.be/seykron/tehanu/blob/master/tehanu-spring/src/main/kotlin/be/rlab/tehanu/SpringApplication.kt)
class. The SpringApplication class automatically wires all bot components and it lets
you initialize your own components. The following example shows how to initialize the SayHello
message listener by using the Spring's DSL for Kotlin:
```kotlin
class Main : SpringApplication() {
override fun initialize() {
val beans = beans {
bean { SayHello(name = "say_hello", botName = "@hellobot") }
}
beans.initialize(applicationContext)
}
}
fun main(args: Array<String>) {
Main().start()
}
```
### Configuration
The *tehanu-spring* module uses the [type safe](https://github.com/lightbend/config)
configuration. The configuration file is named *application.conf* and it must be placed
in the root classpath.
The configuration includes the data source options for the persistent storage.
Make sure you've got a JDBC driver available in your classpath at runtime. The
following configuration assumes you've got the H2 JDBC driver in the classpath:
```
db {
url: "jdbc:h2:file:/tmp/hellobot-db/hellobot"
user: "sa"
password: ""
driver: "org.h2.Driver"
}
bot {
access_token: ${?bot_access_token}
}
```
## Documentation
For the full documentation look at the [wiki](https://git.rlab.be/seykron/tehanu/wikis/home).
......@@ -15,7 +15,7 @@
<h2.version>1.4.197</h2.version>
<tehanu.version>2.1.1-SNAPSHOT</tehanu.version>
<kotlin.version>1.3.40</kotlin.version>
<kotlin.version>1.3.50</kotlin.version>
<kotlin-coroutines.version>1.1.1</kotlin-coroutines.version>
<kotlin.code.style>official</kotlin.code.style>
</properties>
......
package be.rlab.hellobot
import be.rlab.hellobot.SayHello
import org.springframework.context.support.beans
object ApplicationBeans {
fun beans() = beans {
bean {
SayHello(
name = "/can_haz_kitten",
botName = "@hellobot"
)
}
}
}
package be.rlab.hellobot
import be.rlab.tehanu.SpringApplication
import be.rlab.tehanu.util.persistence.DataSourceInitializer
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.getBean
import org.springframework.context.support.beans
class Main : SpringApplication() {
private val logger: Logger = LoggerFactory.getLogger(Main::class.java)
override fun initialize() {
ApplicationBeans.beans().initialize(applicationContext)
}
val beans = beans {
bean { SayHello(name = "say_hello", botName = "@hellobot") }
}
override fun ready() {
logger.info("Initializing data source")
val dataSourceInitializer: DataSourceInitializer = applicationContext.getBean()
dataSourceInitializer.initAuto()
beans.initialize(applicationContext)
}
}
......
db {
url: "jdbc:h2:file:/tmp/hellobot-db/cathulhu"
url: "jdbc:h2:file:/tmp/hellobot-db/hellobot"
user: "sa"
password: ""
driver: "org.h2.Driver"
log-statements: false
drop: "no"
}
bot {
access_token: ${?bot_access_token}
admins: []
roles: [
{ title: "Administrador", name: "ADMIN", permissions: [ "MANAGE_ADMINS" ] }
]
permissions: [
]
}
......@@ -11,10 +11,10 @@ data class BotConfig(
) {
fun isAdmin(userId: Long): Boolean = admins.contains(userId)
fun findRole(roleName: String): Role {
fun findRole(roleName: String): Role? {
return roles.find { role ->
role.name == roleName
} ?: throw RuntimeException("Role not found")
}
}
fun findPermissions(listenerName: String): List<String> {
......
......@@ -58,7 +58,7 @@ class AccessControl(
val userPermissions: List<String> = userRoleInChat.rolesNames.map { roleName ->
config.findRole(roleName)
}.flatMap { role ->
role.permissions
role?.permissions ?: emptyList()
}
logger.info("Required permissions: ${requiredPermissions.joinToString()}")
logger.info("User ${userInfo(chat, user)} has permissions: $userPermissions")
......@@ -71,7 +71,7 @@ class AccessControl(
return userRoles.filterValues { userRoles ->
userRoles.any { userRole ->
val isAdmin: Boolean = userRole.rolesNames.any { roleName ->
config.findRole(roleName).admin
config.findRole(roleName)?.admin ?: false
}
userRole.chatId == chat.id && isAdmin
......
......@@ -4,8 +4,11 @@ import be.rlab.tehanu.config.BotBeans
import be.rlab.tehanu.config.DataSourceBeans
import be.rlab.tehanu.config.MemoryBeans
import be.rlab.tehanu.domain.Tehanu
import be.rlab.tehanu.domain.persistence.MemorySlots
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.transaction
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.slf4j.bridge.SLF4JBridgeHandler
......@@ -62,6 +65,11 @@ abstract class SpringApplication : BotApplication {
}
initialize()
applicationContext.refresh()
transaction {
SchemaUtils.createMissingTablesAndColumns(MemorySlots)
}
ready()
val tehanu: Tehanu = applicationContext.getBean()
......
......@@ -8,6 +8,7 @@ import be.rlab.tehanu.domain.*
import be.rlab.tehanu.domain.model.ChatType
import be.rlab.tehanu.domain.model.ListenerPermissions
import be.rlab.tehanu.domain.model.Role
import be.rlab.tehanu.util.ConfigUtils.getOrDefault
import com.typesafe.config.Config
import org.slf4j.Logger
import org.slf4j.LoggerFactory
......@@ -69,16 +70,18 @@ object BotBeans {
bean {
logger.info("Loading bot configuration")
val roles: List<Role> = botConfig.getConfigList("roles").map { roleConfig ->
val roles: List<Role> = botConfig.getOrDefault(emptyList()) {
getConfigList("roles")
}.map { roleConfig ->
Role(
name = roleConfig.getString("name"),
title = roleConfig.getString("title"),
permissions = roleConfig.getStringList("permissions")
)
}
val permissions: List<ListenerPermissions> = botConfig.getConfigList(
"permissions"
).map { permissionsConfig ->
val permissions: List<ListenerPermissions> = botConfig.getOrDefault(emptyList()) {
getConfigList("permissions")
}.map { permissionsConfig ->
ListenerPermissions(
listenerName = permissionsConfig.getString("listener_name"),
requiredPermissions = permissionsConfig.getStringList("required_permissions")
......@@ -87,7 +90,7 @@ object BotBeans {
BotConfig(
accessToken = botConfig.getString("access_token"),
admins = botConfig.getLongList("admins"),
admins = botConfig.getOrDefault(emptyList()) { getLongList("admins") },
roles = roles,
listenersPermissions = permissions
)
......
package be.rlab.tehanu.config
import be.rlab.tehanu.util.persistence.DataSourceInitializer
import be.rlab.tehanu.util.ConfigUtils.getOrDefault
import com.typesafe.config.Config
import com.zaxxer.hikari.HikariDataSource
import org.jetbrains.exposed.sql.Database
......@@ -25,8 +26,8 @@ object DataSourceBeans {
user = dbConfig.getString("user"),
password = dbConfig.getString("password"),
driver = dbConfig.getString("driver"),
logStatements = dbConfig.getBoolean("log-statements"),
drop = dbConfig.getString("drop")
logStatements = dbConfig.getOrDefault(false) { getBoolean("log-statements") },
drop = dbConfig.getOrDefault("no") { getString("drop") }
)
}
......
package be.rlab.tehanu.util
import com.typesafe.config.Config
import com.typesafe.config.ConfigException
object ConfigUtils {
fun<T> Config.getOrDefault(
defaultValue: T,
resolve: Config.() -> T
): T {
return try {
resolve(this)
} catch (cause: ConfigException) {
defaultValue
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment