Skip to content

Commit 85b64e3

Browse files
committed
Added a CLI command for access logging.
1 parent 8f911ec commit 85b64e3

File tree

2 files changed

+113
-1
lines changed

2 files changed

+113
-1
lines changed

src/main/kotlin/ch/pontius/swissqr/api/cli/Cli.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class Cli(val dataAccessLayer: DataAccessLayer, val config: Config) {
3535
}
3636
}.subcommands(
3737
UserCommand(this.dataAccessLayer.userStore, this.dataAccessLayer.tokenStore),
38-
TokenCommand(this.dataAccessLayer.tokenStore, this.dataAccessLayer.userStore)
38+
TokenCommand(this.dataAccessLayer.tokenStore, this.dataAccessLayer.userStore),
39+
LogCommand(this.dataAccessLayer.accessLogs)
3940
)
4041

4142
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package ch.pontius.swissqr.api.cli
2+
3+
import ch.pontius.swissqr.api.db.ListStore
4+
import ch.pontius.swissqr.api.model.access.Access
5+
import ch.pontius.swissqr.api.model.users.TokenId
6+
import ch.pontius.swissqr.api.model.users.User
7+
import com.github.ajalt.clikt.core.CliktCommand
8+
import com.github.ajalt.clikt.core.NoOpCliktCommand
9+
import com.github.ajalt.clikt.core.subcommands
10+
import com.github.ajalt.clikt.parameters.options.convert
11+
import com.github.ajalt.clikt.parameters.options.default
12+
import com.github.ajalt.clikt.parameters.options.option
13+
import com.github.ajalt.clikt.parameters.options.required
14+
import com.jakewharton.picnic.Table
15+
import com.jakewharton.picnic.table
16+
17+
/**
18+
* A collection of [CliktCommand]s to query and manipulate the [Access] logs.
19+
*
20+
* @author Ralph Gasser
21+
* @version 1.0.0
22+
*/
23+
class LogCommand(private val logStore: ListStore<Access>) : NoOpCliktCommand(name = "log") {
24+
25+
init {
26+
this.subcommands(ListLogsCommand())
27+
}
28+
29+
/** List of defined aliases for this [UserCommand]. */
30+
override fun aliases(): Map<String, List<String>> {
31+
return mapOf(
32+
"ls" to listOf("list"),
33+
"delete" to listOf("invalidate"),
34+
"remove" to listOf("invalidate"),
35+
"drop" to listOf("invalidate"),
36+
"add" to listOf("create")
37+
)
38+
}
39+
40+
/**
41+
* Tabulates the given [Iterable] of [User] objects.
42+
*
43+
* @param users [Iterable] of [User] objects
44+
* @return Resulting [Table]
45+
*/
46+
private fun tabulateAccessLogs(users: Iterable<Access?>): Table = table {
47+
cellStyle {
48+
border = true
49+
paddingLeft = 1
50+
paddingRight = 1
51+
}
52+
header {
53+
row("tokenId", "source", "path", "method", "status", "timestamp")
54+
}
55+
body {
56+
users.forEach {
57+
if (it != null) {
58+
row(it.tokenId, it.ip, it.path, it.method, it.status, it.timestamp)
59+
}
60+
}
61+
}
62+
}
63+
64+
/**
65+
* [CliktCommand] to list all available [User]s.
66+
*/
67+
inner class ListLogsCommand : CliktCommand(name = "list", help = "Lists all access log entries.") {
68+
69+
/** The [TokenId] to invalidate. */
70+
private val tokenId: TokenId? by option("-i", "--id").convert { TokenId(it) }
71+
72+
/** Flag that can be set to only list active tokens. */
73+
private val status: Int? by option("-s", "--status", help = "Only lists entries that match the given status.")
74+
.convert { it.toInt() }
75+
76+
/** Flag that can be set to only list active tokens. */
77+
private val after: Long by option("-a", "--after", help = "Only lists entries that happened after the given timestamp.")
78+
.convert { it.toLong() }
79+
.default(Long.MIN_VALUE)
80+
81+
/** Flag that can be set to only list active tokens. */
82+
private val before: Long by option("-b", "--before", help = "Only lists entries that happened before the given timestamp.")
83+
.convert { it.toLong() }
84+
.default(Long.MAX_VALUE)
85+
86+
/** Flag that can be set to only list active tokens. */
87+
private val limit: Int by option("-l", "--limit", help = "Only lists entries that happened before the given timestamp.")
88+
.convert { it.toInt() }
89+
.default(100)
90+
91+
override fun run() {
92+
val logs = this@LogCommand.logStore.filter {
93+
var match = false
94+
if (it != null) {
95+
match = (it.timestamp > this.after && it.timestamp < this.before)
96+
if (this.status != null) {
97+
match = match && (it.status == this.status)
98+
}
99+
if (this.status != null) {
100+
match = match && (it.status == this.status)
101+
}
102+
if (this.tokenId != null) {
103+
match = match && (it.tokenId == this.tokenId)
104+
}
105+
}
106+
match
107+
}.takeLast(this.limit)
108+
println(this@LogCommand.tabulateAccessLogs(logs))
109+
}
110+
}
111+
}

0 commit comments

Comments
 (0)