Push first proper version

master
Julius 2020-03-16 16:16:07 +01:00
parent 7cad13248a
commit fff2f8698f
10 changed files with 219 additions and 53 deletions

9
.dockerignore Normal file
View File

@ -0,0 +1,9 @@
.idea/
.gradle/
build/
out/
test.db
gradle/
gradlew
gradlew.bat
.gitignore

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
.gradle/
build/
out/
test.db

27
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,27 @@
image: docker:latest
services:
- docker:dind
stages:
- build
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:latest
NAME: $CI_PROJECT_NAME
DOCKER_BUILDKIT: 1
build_and_push:
stage: build
only:
- master
script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.voidcorp.nl
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
only_build:
stage: build
except:
- master
script:
- docker build -t $IMAGE_TAG .

12
Dockerfile Normal file
View File

@ -0,0 +1,12 @@
FROM gradle:jdk11 as builder
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build
FROM openjdk:11-jre-slim
COPY --from=builder /home/gradle/src/build/distributions/watchtower.tar /app/watchtower.tar
WORKDIR /app
RUN tar -xvf watchtower.tar
WORKDIR /app/watchtower
CMD bin/watchtower

View File

@ -1,6 +1,7 @@
plugins {
java
kotlin("jvm") version "1.3.61"
application
kotlin("jvm") version "1.3.70"
}
group = "nl.voidcorp"
@ -10,11 +11,21 @@ repositories {
jcenter()
}
fun DependencyHandlerScope.exposed(part: String) = implementation("org.jetbrains.exposed", part, "0.22.1")
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation("net.dv8tion:JDA:4.1.1_108")
implementation("net.dv8tion:JDA:4.1.1_108") {
exclude(module = "opus-java")
}
testImplementation("junit", "junit", "4.12")
implementation("ch.qos.logback:logback-classic:1.2.3")
exposed("exposed-core")
exposed("exposed-dao")
exposed("exposed-jdbc")
implementation("org.xerial:sqlite-jdbc:3.30.1")
implementation("com.impossibl.pgjdbc-ng:pgjdbc-ng:0.8.3")
}
configure<JavaPluginConvention> {
@ -27,4 +38,14 @@ tasks {
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
distTar {
archiveName = "watchtower.tar"
}
}
application {
applicationName = "watchtower"
mainClassName = "nl.voidcorp.watchtower.MainKt"
}

View File

@ -1,2 +1,2 @@
rootProject.name = "OttoLogs"
rootProject.name = "WatchTower"

View File

@ -1,49 +0,0 @@
package nl.voidcorp.ottologs
import net.dv8tion.jda.api.EmbedBuilder
import net.dv8tion.jda.api.JDABuilder
import net.dv8tion.jda.api.entities.Activity
import net.dv8tion.jda.api.events.message.guild.GuildMessageDeleteEvent
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent
import net.dv8tion.jda.api.hooks.ListenerAdapter
import java.awt.Color
fun main() {
val token: String = System.getenv("DISCORD_TOKEN") ?: throw RuntimeException("Missing DISCORD_TOKEN in env!")
val jda = JDABuilder().setToken(token).setActivity(Activity.watching("you")).addEventListeners(LogListener).build()
}
data class Message(val user: Long, val content: String, val channel: Long, val guild: Long, val message: Long)
val messages = mutableListOf<Message>()
object LogListener : ListenerAdapter() {
override fun onGuildMessageReceived(event: GuildMessageReceivedEvent) {
if (!event.isWebhookMessage && !event.author.isBot) {
val m = Message(
event.author.idLong,
event.message.contentRaw,
event.message.channel.idLong,
event.guild.idLong,
event.message.idLong
)
messages += m
}
}
override fun onGuildMessageDelete(event: GuildMessageDeleteEvent) {
val m = messages.firstOrNull { it.message == event.messageIdLong } ?: return
val logs = event.guild.textChannels.find { it.name == "logs" }
logs?.sendMessage(
EmbedBuilder().setDescription(m.content).setTitle("Message Deleted!")
.addField("Channel", event.channel.asMention, true).addField(
"User",
event.jda.getUserById(m.user)?.asTag ?: "No Idea...",
true
).setColor(Color.RED)
.build()
)?.queue {
}
}
}

View File

@ -0,0 +1,37 @@
package nl.voidcorp.watchtower
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.id.EntityID
import org.jetbrains.exposed.sql.transactions.transaction
class Message(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Message>(Messages)
var user by Messages.user
var channel by Messages.channel
var guild by Messages.guild
var message by Messages.message
val history by MessageHistory referrersOn MessageHistories.original
fun update(new: String) {
transaction {
MessageHistory.new {
content = new
original = this@Message
}
}
}
val lastVersion
get() = history.maxBy { it.updated }!!
}
class MessageHistory(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<MessageHistory>(MessageHistories)
var content by MessageHistories.content
var updated by MessageHistories.updated
var original by Message referencedOn MessageHistories.original
}

View File

@ -0,0 +1,92 @@
package nl.voidcorp.watchtower
import net.dv8tion.jda.api.EmbedBuilder
import net.dv8tion.jda.api.JDABuilder
import net.dv8tion.jda.api.entities.Activity
import net.dv8tion.jda.api.events.message.guild.GenericGuildMessageEvent
import net.dv8tion.jda.api.events.message.guild.GuildMessageDeleteEvent
import net.dv8tion.jda.api.events.message.guild.GuildMessageReceivedEvent
import net.dv8tion.jda.api.events.message.guild.GuildMessageUpdateEvent
import net.dv8tion.jda.api.hooks.ListenerAdapter
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.jetbrains.exposed.sql.transactions.transaction
import java.awt.Color
import java.sql.Connection
import java.time.Instant
fun main() {
val token: String = System.getenv("DISCORD_TOKEN") ?: throw RuntimeException("Missing DISCORD_TOKEN in env!")
Database.connect(
System.getenv("JDBC_URl") ?: "jdbc:sqlite:test.db",
System.getenv("JDBC_DRIVER") ?: "org.sqlite.JDBC"
)
TransactionManager.manager.defaultIsolationLevel = Connection.TRANSACTION_SERIALIZABLE
transaction {
SchemaUtils.createMissingTablesAndColumns(Messages, MessageHistories)
}
JDABuilder().setToken(token).setActivity(Activity.watching("you")).addEventListeners(LogListener).build()
}
fun GuildMessageReceivedEvent.log() {
transaction {
Message.new {
channel = this@log.channel.idLong
user = this@log.author.idLong
guild = this@log.guild.idLong
message = this@log.messageIdLong
}.update(this@log.message.contentRaw)
}
}
object LogListener : ListenerAdapter() {
override fun onGuildMessageReceived(event: GuildMessageReceivedEvent) {
if (!event.isWebhookMessage && !event.author.isBot) {
event.log()
}
}
override fun onGuildMessageUpdate(event: GuildMessageUpdateEvent) {
if (!event.author.isBot) {
val m = transaction { Message.find { Messages.message eq event.messageIdLong }.firstOrNull() } ?: return
m.update(event.message.contentRaw)
messageEdit(event, "Message Edited!")
}
}
override fun onGuildMessageDelete(event: GuildMessageDeleteEvent) {
messageEdit(event, "Message Deleted!")
}
private fun messageEdit(event: GenericGuildMessageEvent, what: String) {
val m = transaction { Message.find { Messages.message eq event.messageIdLong }.firstOrNull() } ?: return
val logs = event.guild.textChannels.find { it.name == "logs" }
logs?.sendMessage(
EmbedBuilder().setDescription(transaction { m.lastVersion.content }).setTitle(what)
.addField("Channel", event.channel.asMention, true).addField(
"User",
event.jda.getUserById(m.user)?.asTag ?: "No Idea...",
true
).setColor(Color.ORANGE.let {
if (what.contains("delete", true)) Color.RED.darker() else it
}).apply {
this.addField(
"History",
transaction {
m.history.sortedBy { it.updated }.dropLast(1).joinToString("\n") { it.content }
}, false
)
}.setTimestamp(Instant.ofEpochMilli(transaction { m.lastVersion.updated })).setFooter("Last changed at")
.build()
)?.queue {
if (event is GuildMessageDeleteEvent) {
transaction {
MessageHistory.find { MessageHistories.original eq m.id }.forEach { it.delete() }
m.delete()
}
}
}
}
}

View File

@ -0,0 +1,16 @@
package nl.voidcorp.watchtower
import org.jetbrains.exposed.dao.id.IntIdTable
object Messages : IntIdTable() {
val user = long("user")
val channel = long("channel")
val guild = long("guild")
val message = long("message")
}
object MessageHistories : IntIdTable() {
val original = reference("original", Messages)
val content = text("content")
val updated = long("updated").clientDefault { System.currentTimeMillis() }
}