diff --git a/.gitignore b/.gitignore index 58d7bc4..9981e28 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ data/ *.swo *.db +twitter.toml diff --git a/build.gradle b/build.gradle index 899f05e..fb47a9d 100644 --- a/build.gradle +++ b/build.gradle @@ -97,6 +97,10 @@ kotlin { implementation "com.soywiz:klock-jvm:$klockVersion" implementation "com.soywiz:klock-locale-jvm:$klockVersion" + //implementation 'com.twitter:hbc-core:2.2.0' + //implementation 'com.twitter:hbc-twitter4j:2.2.0' + api 'org.twitter4j:twitter4j-stream:4.0.1' + implementation 'com.github.uchuhimo:konf:master-SNAPSHOT' implementation 'com.vladsch.flexmark:flexmark-all:0.42.10' api 'io.github.microutils:kotlin-logging:1.6.23' diff --git a/portal.toml b/portal.toml index 4c1c7d1..f42a9d4 100644 --- a/portal.toml +++ b/portal.toml @@ -3,7 +3,7 @@ host = "localhost" port = 8080 [schedule] -reference = "2019-06-04" +reference = "2019-06-06" [general] wiki_url = "https://wiki.kif.rocks/w/index.php?title=KIF470:Arbeitskreise&action=raw" diff --git a/src/jsMain/kotlin/de/kif/frontend/repository/Ajax.kt b/src/jsMain/kotlin/de/kif/frontend/repository/Ajax.kt index d1f7d00..a08991d 100644 --- a/src/jsMain/kotlin/de/kif/frontend/repository/Ajax.kt +++ b/src/jsMain/kotlin/de/kif/frontend/repository/Ajax.kt @@ -11,7 +11,6 @@ import kotlin.js.Promise suspend fun repositoryGet( url: String ): dynamic { - console.log("GET: $url") val promise = Promise { resolve, reject -> val xhttp = XMLHttpRequest() @@ -48,7 +47,6 @@ suspend fun repositoryPost( url: String, data: String? = null ): dynamic { - console.log("POST: $url", data) val promise = Promise { resolve, reject -> val xhttp = XMLHttpRequest() @@ -85,7 +83,6 @@ suspend fun repositoryPost( suspend fun repositoryRawGet( url: String ): String { - console.log("GET: $url") val promise = Promise { resolve, reject -> val xhttp = XMLHttpRequest() diff --git a/src/jsMain/kotlin/de/kif/frontend/views/calendar/Calendar.kt b/src/jsMain/kotlin/de/kif/frontend/views/calendar/Calendar.kt index a992836..b5ca675 100644 --- a/src/jsMain/kotlin/de/kif/frontend/views/calendar/Calendar.kt +++ b/src/jsMain/kotlin/de/kif/frontend/views/calendar/Calendar.kt @@ -4,9 +4,9 @@ import de.kif.frontend.iterator import de.kif.frontend.launch import de.kif.frontend.repository.ScheduleRepository import de.westermann.kwebview.View -import de.westermann.kwebview.createHtmlView import org.w3c.dom.* import kotlin.browser.document +import kotlin.browser.window class Calendar(calendar: HTMLElement) : View(calendar) { @@ -15,23 +15,23 @@ class Calendar(calendar: HTMLElement) : View(calendar) { val day: Int - val htmlTag = document.documentElement as HTMLHtmlElement + val htmlTag = document.body as HTMLElement val calendarTable = calendar.getElementsByClassName("calendar-table")[0] as HTMLElement - fun scrollVerticalBy(pixel: Double) { - htmlTag.scrollBy(ScrollToOptions(0.0, pixel, ScrollBehavior.SMOOTH)) + fun scrollVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) { + htmlTag.scrollBy(ScrollToOptions(0.0, pixel, scrollBehavior)) } - fun scrollHorizontalBy(pixel: Double) { - calendarTable.scrollBy(ScrollToOptions(pixel, 0.0, ScrollBehavior.SMOOTH)) + fun scrollHorizontalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) { + calendarTable.scrollBy(ScrollToOptions(pixel, 0.0, scrollBehavior)) } - fun scrollVerticalTo(pixel: Double) { - htmlTag.scrollTo(ScrollToOptions(0.0, pixel, ScrollBehavior.SMOOTH)) + fun scrollVerticalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) { + htmlTag.scrollTo(ScrollToOptions(0.0, pixel, scrollBehavior)) } - fun scrollHorizontalTo(pixel: Double) { - calendarTable.scrollTo(ScrollToOptions(pixel, 0.0, ScrollBehavior.SMOOTH)) + fun scrollHorizontalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) { + calendarTable.scrollTo(ScrollToOptions(pixel, 0.0, scrollBehavior)) } init { @@ -78,8 +78,7 @@ class Calendar(calendar: HTMLElement) : View(calendar) { } } - val view = View.wrap(document.getElementById("calendar-check-constraints") as HTMLElement) - view.onClick { + (document.getElementById("calendar-check-constraints") as? HTMLElement)?.let { wrap(it) }?.onClick?.addListener { launch { val errors = ScheduleRepository.checkConstraints() @@ -94,6 +93,19 @@ class Calendar(calendar: HTMLElement) : View(calendar) { } } } + + onWheel { + val multiplier = when (it.deltaMode) { + 1 -> 16.0 + 2 -> window.innerHeight.toDouble() + else -> 1.0 + } + + scrollHorizontalBy(it.deltaX * multiplier, ScrollBehavior.INSTANT) + scrollVerticalBy(it.deltaY * multiplier, ScrollBehavior.INSTANT) + + it.preventDefault() + } } } diff --git a/src/jvmMain/kotlin/de/kif/backend/Application.kt b/src/jvmMain/kotlin/de/kif/backend/Application.kt index c48c23e..ab3eabc 100644 --- a/src/jvmMain/kotlin/de/kif/backend/Application.kt +++ b/src/jvmMain/kotlin/de/kif/backend/Application.kt @@ -15,6 +15,7 @@ import io.ktor.jackson.jackson import io.ktor.response.respond import io.ktor.routing.routing import io.ktor.websocket.WebSockets +import java.nio.file.Paths fun Application.main() { install(DefaultHeaders) @@ -49,6 +50,13 @@ fun Application.main() { files(Configuration.Path.uploadsPath.toFile()) } + val srcFile = Paths.get("src")?.toFile() + if (srcFile != null && srcFile.exists() && srcFile.isDirectory) { + static("/src") { + files("src") + } + } + // UI routes overview() calendar() diff --git a/src/jvmMain/kotlin/de/kif/backend/Configuration.kt b/src/jvmMain/kotlin/de/kif/backend/Configuration.kt index 5c8efc5..53b4395 100644 --- a/src/jvmMain/kotlin/de/kif/backend/Configuration.kt +++ b/src/jvmMain/kotlin/de/kif/backend/Configuration.kt @@ -4,6 +4,7 @@ import com.uchuhimo.konf.Config import com.uchuhimo.konf.ConfigSpec import com.uchuhimo.konf.Item import java.io.FileNotFoundException +import java.nio.file.Files import java.nio.file.Paths import java.text.SimpleDateFormat import java.time.ZoneId @@ -89,6 +90,16 @@ object Configuration { val wikiUrl by c(GeneralSpec.wikiUrl) } + private object TwitterSpec : ConfigSpec("twitter") { + val username by required("username") + val password by required("password") + } + + object Twitter { + val username by c(TwitterSpec.username) + val password by c(TwitterSpec.password) + } + init { var config = Config { addSpec(ServerSpec) @@ -96,11 +107,16 @@ object Configuration { addSpec(ScheduleSpec) addSpec(SecuritySpec) addSpec(GeneralSpec) + addSpec(TwitterSpec) }.from.toml.resource("portal.toml") - try { - config = config.from.toml.file("portal.toml") - } catch (_: FileNotFoundException) { + for (file in Files.list(Paths.get("."))) { + if (file.fileName.toString().endsWith(".toml")) { + try { + config = config.from.toml.file(file.toFile()) + } catch (_: FileNotFoundException) { + } + } } this.config = config.from.env() diff --git a/src/jvmMain/kotlin/de/kif/backend/Main.kt b/src/jvmMain/kotlin/de/kif/backend/Main.kt index 2618002..2df11b7 100644 --- a/src/jvmMain/kotlin/de/kif/backend/Main.kt +++ b/src/jvmMain/kotlin/de/kif/backend/Main.kt @@ -18,6 +18,8 @@ object Main { Connection.init() + // twitter() + runBlocking { if (UserRepository.all().isEmpty()) { diff --git a/src/jvmMain/kotlin/de/kif/backend/Twitter.kt b/src/jvmMain/kotlin/de/kif/backend/Twitter.kt new file mode 100644 index 0000000..dd09637 --- /dev/null +++ b/src/jvmMain/kotlin/de/kif/backend/Twitter.kt @@ -0,0 +1,142 @@ +package de.kif.backend + +import twitter4j.* +import twitter4j.conf.ConfigurationBuilder + + +/* +fun twitter() { + val msgQueue = LinkedBlockingQueue(100000) + val eventQueue = LinkedBlockingQueue(1000) + + val hosts = HttpHosts(Constants.STREAM_HOST) + + val filterEndpoint = StatusesFilterEndpoint() + filterEndpoint.trackTerms(listOf("kif")) + + println(Configuration.Twitter.username) + println(Configuration.Twitter.password) + + val authentication = BasicAuth( + Configuration.Twitter.username, + Configuration.Twitter.password + ) + + val builder = ClientBuilder() + .name("kif-portal") + .hosts(hosts) + .authentication(authentication) + .endpoint(filterEndpoint) + .processor(StringDelimitedProcessor(msgQueue)) + .eventMessageQueue(eventQueue) + + val client = builder.build() + + val listener = object: StatusStreamHandler { + override fun onUnknownMessageType(msg: String?) { + println("onUnknownMessageType") + println(msg) + } + + override fun onDisconnectMessage(message: DisconnectMessage?) { + println("onDisconnectMessage") + println(message?.disconnectReason) + } + + override fun onStallWarningMessage(warning: StallWarningMessage?) { + println("onStallWarningMessage") + println(warning?.message) + } + + override fun onTrackLimitationNotice(numberOfLimitedStatuses: Int) { + println("onTrackLimitationNotice") + println(numberOfLimitedStatuses) + } + + override fun onStallWarning(warning: StallWarning?) { + println("onStallWarning") + println(warning?.message) + } + + override fun onException(ex: Exception?) { + println("onException") + ex?.printStackTrace() + } + + override fun onDeletionNotice(statusDeletionNotice: StatusDeletionNotice?) { + println("onDeletionNotice") + println(statusDeletionNotice?.statusId) + } + + override fun onStatus(status: Status?) { + println("onStatus") + println(status?.text) + } + + override fun onScrubGeo(userId: Long, upToStatusId: Long) { + println("onScrubGeo") + } + + } + + val t4jClient = Twitter4jStatusClient( + client, + msgQueue, + listOf(listener), + Executors.newFixedThreadPool(4) + ) + + t4jClient.connect() + + t4jClient.process() + + while (true) { + + } +} + */ + +fun twitter() { + val cb = ConfigurationBuilder() + cb.setDebugEnabled(true) + .setUser(Configuration.Twitter.username) + .setPassword(Configuration.Twitter.password) + + val listener = object : StatusListener { + + override fun onTrackLimitationNotice(numberOfLimitedStatuses: Int) { + println("onTrackLimitationNotice") + println(numberOfLimitedStatuses) + } + + override fun onStallWarning(warning: StallWarning?) { + println("onStallWarning") + println(warning?.message) + } + + override fun onException(ex: Exception?) { + println("onException") + ex?.printStackTrace() + } + + override fun onDeletionNotice(statusDeletionNotice: StatusDeletionNotice?) { + println("onDeletionNotice") + println(statusDeletionNotice?.statusId) + } + + override fun onStatus(status: Status?) { + println("onStatus") + println(status?.text) + } + + override fun onScrubGeo(userId: Long, upToStatusId: Long) { + println("onScrubGeo") + } + } + + val twitterStream = TwitterStreamFactory(cb.build()).instance + + addTwitterStreamListener(twitterStream, listener) + + twitterStream.sample() +} \ No newline at end of file diff --git a/src/jvmMain/kotlin/twitter4j/AddListener.kt b/src/jvmMain/kotlin/twitter4j/AddListener.kt new file mode 100644 index 0000000..567207f --- /dev/null +++ b/src/jvmMain/kotlin/twitter4j/AddListener.kt @@ -0,0 +1,5 @@ +package twitter4j + +fun addTwitterStreamListener(stream: TwitterStream, listener: StatusListener) { + stream.addListener(listener) +} diff --git a/src/jvmMain/resources/portal.toml b/src/jvmMain/resources/portal.toml index 2f6f76b..41a88e8 100644 --- a/src/jvmMain/resources/portal.toml +++ b/src/jvmMain/resources/portal.toml @@ -18,3 +18,7 @@ sign_key = "d1 20 23 8c 01 f8 f0 0d 9d 7c ff 68 21 97 75 31 38 3f fb 91 20 3a 8d [general] allowed_upload_extensions = "png, jpg, jpeg" wiki_url = "" + +[twitter] +username = "" +password = ""