Skip to content
Permalink
Browse files

Add support for SimpleAnalytics as stats provider

Signed-off-by: Till Kottmann <me@deletescape.ch>
  • Loading branch information
deletescape committed Oct 24, 2019
1 parent 2b0fb39 commit 7b281ba96f07bdef273942c019dd96644c6c8382
@@ -15,15 +15,22 @@ application {

dependencies {
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version")
compile("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.3.2")
compile("io.ktor:ktor-server-netty:$ktor_version")
compile("ch.qos.logback:logback-classic:$logback_version")
compile("io.ktor:ktor-metrics:$ktor_version")
compile("io.ktor:ktor-server-core:$ktor_version")
compile("io.ktor:ktor-gson:$ktor_version")
compile("io.ktor:ktor-client-core:$ktor_version")
compile("io.ktor:ktor-client-apache:$ktor_version")
compile("io.ktor:ktor-client-gson:$ktor_version")
compile("org.apache.httpcomponents:httpasyncclient:4.1.4")
compile(project(":pebble"))

compile("com.github.zensum:ktor-health-check:011a5a8")
compile("org.koin:koin-ktor:$koin_version")
compile("net.jodah:expiringmap:0.5.9")
compile("com.github.ben-manes.caffeine:caffeine:2.8.0")
compile(project(":data:base"))
compile(project(":commons"))

@@ -8,6 +8,8 @@ ktor {
}
}
dogbin {
host = "localhost"
host = ${?HOST}
db {
location = "dogbin.xdb"
location = ${?DB_LOCATION}
@@ -20,4 +22,12 @@ dogbin {
session = "DEADBEEF"
session = ${?SESSION_KEY}
}
}
stats {
enabled = true
enabled = ${?COLLECT_STATS}

// Whether to use SimpleAnalytics for stats (querying SA for view count and reporting redirects to SA)
useSA = false
useSA = ${?SIMPLEANALYTICS}
}
}
@@ -83,4 +83,5 @@
var app = new haste();
});
</script>
{{ stats_embed | raw }}
{% endblock %}
@@ -12,21 +12,25 @@
<div id="content">
<div class="center-inside">
<div class="card">
<h1>{{ user.username }}</h1>
<p>Joined: {{ user.created }}</p>
{% if pastes is not empty %}
<h2>Documents</h2>
{% for paste in pastes %}
<p><a href="/{{ paste.slug }}">{{ paste.slug }}</a> ({{ paste.created }})</p>
{% endfor %}
{% endif %}
<a class="md-btn md-btn-secondary left" href="/me/changepass"><span>CHANGE PASSWORD</span></a>
<a class="md-btn md-btn-secondary right" href="/logout"><span>LOG OUT</span></a>
</code></div>
<h1>{{ user.username }}</h1>
<p>Joined: {{ user.created }}</p>
{% if pastes is not empty %}
<h2>Documents</h2>
{% for paste in pastes %}
<p><a href="/{{ paste.slug }}">{{ paste.slug }}</a> ({{ paste.created }})</p>
{% endfor %}
{% endif %}
<a class="md-btn md-btn-secondary left" href="/me/changepass"><span>CHANGE PASSWORD</span></a>
<a class="md-btn md-btn-secondary right" href="/logout"><span>LOG OUT</span></a>
</code></div>
</div>
</div>
<div id="footer" class="unselectable">
<div id="copyright">&copy; {{ year }} <a href="https://deletescape.ch" target="_blank" rel="noopener">deletescape</a>
<div id="copyright">&copy; {{ year }} <a href="https://deletescape.ch" target="_blank"
rel="noopener">deletescape</a>
</div>
</div>
{% endblock %}
{% endblock %}
{% block after_body %}
{{ stats_embed | raw }}
{% endblock %}
@@ -8,12 +8,18 @@ import dog.del.app.frontend.legacyApi
import dog.del.app.session.ApiSession
import dog.del.app.session.WebSession
import dog.del.app.session.XdSessionStorage
import dog.del.app.stats.StatisticsReporter
import dog.del.app.utils.DogbinPebbleExtension
import dog.del.commons.keygen.KeyGenerator
import dog.del.commons.keygen.PhoneticKeyGenerator
import dog.del.data.base.Database
import dog.del.data.base.model.config.Config
import io.ktor.application.*
import io.ktor.client.HttpClient
import io.ktor.client.engine.apache.Apache
import io.ktor.client.features.json.GsonSerializer
import io.ktor.client.features.json.JsonFeature
import io.ktor.client.features.json.JsonSerializer
import io.ktor.features.*
import io.ktor.routing.*
import io.ktor.gson.*
@@ -60,6 +66,15 @@ fun Application.module(testing: Boolean = false) {
single { Database.init(appConfig.db.location, appConfig.db.environment) }
single { Config.getConfig(get()) }
single<KeyGenerator> { PhoneticKeyGenerator() }
single { StatisticsReporter.getReporter(appConfig) }
single { this@module.log }
single {
HttpClient(Apache) {
install(JsonFeature) {
serializer = GsonSerializer()
}
}
}
}
modules(
appModule
@@ -6,6 +6,8 @@ import java.io.File


class AppConfig(config: ApplicationConfig) {
val host = config.property("dogbin.host").getString()

val db = DbConfig(
location = File(config.property("dogbin.db.location").getString()),
environment = config.property("dogbin.db.environment").getString()
@@ -15,6 +17,12 @@ class AppConfig(config: ApplicationConfig) {
session = hex(config.property("dogbin.keys.session").getString())
)

val stats = Stats(
enabled = config.property("dogbin.stats.enabled").getString().toBoolean(),
useSA = config.property("dogbin.stats.useSA").getString().toBoolean()
)

data class DbConfig(val location: File, val environment: String)
data class Keys(val session: ByteArray)
data class Stats(val enabled: Boolean, val useSA: Boolean)
}
@@ -1,12 +1,14 @@
package dog.del.app.dto

import dog.del.app.stats.StatisticsReporter
import dog.del.commons.format
import dog.del.commons.formatLong
import dog.del.commons.formatShort
import dog.del.commons.lineCount
import dog.del.data.base.model.document.XdDocumentType
import dog.del.data.model.Document
import dog.del.data.model.DocumentType
import kotlinx.coroutines.runBlocking
import java.util.*

data class FrontendDocumentDto(
@@ -24,15 +26,22 @@ data class FrontendDocumentDto(
// Use frontmatter data for rendered markdown content
val description = content?.take(100) ?: "The sexiest pastebin and url-shortener ever"
val title = "dogbin - $slug"

companion object {
fun fromDocument(document: Document<XdDocumentType, *>, locale: Locale? = null) = FrontendDocumentDto(
document.slug,
DocumentTypeDto.fromXdDocumentType(document.type),
document.stringContent,
UserDto.fromUser(document.owner),
document.created.formatShort(locale),
document.viewCount
)
fun fromDocument(
document: Document<XdDocumentType, *>,
reporter: StatisticsReporter? = null,
locale: Locale? = null
) = runBlocking {
FrontendDocumentDto(
document.slug,
DocumentTypeDto.fromXdDocumentType(document.type),
document.stringContent,
UserDto.fromUser(document.owner),
document.created.formatShort(locale),
reporter?.getImpressions(document.slug) ?: document.viewCount
)
}
}
}

@@ -47,11 +56,11 @@ data class CreateDocumentResponseDto(
val message: String? = null
)

enum class DocumentTypeDto{
enum class DocumentTypeDto {
URL, PASTE;

companion object {
fun fromXdDocumentType(documentType: XdDocumentType) = when(documentType) {
fun fromXdDocumentType(documentType: XdDocumentType) = when (documentType) {
XdDocumentType.PASTE -> PASTE
XdDocumentType.URL -> URL
else -> throw IllegalStateException()
@@ -3,31 +3,33 @@ package dog.del.app.frontend
import dog.del.app.dto.FrontendDocumentDto
import dog.del.app.session.session
import dog.del.app.session.user
import dog.del.app.stats.StatisticsReporter
import dog.del.app.stats.StatisticsReporter.*
import dog.del.app.utils.locale
import dog.del.app.utils.slug
import dog.del.commons.Date
import dog.del.commons.year
import dog.del.data.base.Database
import dog.del.data.base.model.document.XdDocument
import dog.del.data.base.model.document.XdDocumentType
import dog.del.data.model.DocumentType
import io.ktor.application.call
import io.ktor.pebble.respondTemplate
import io.ktor.response.respondRedirect
import io.ktor.routing.Route
import io.ktor.routing.get
import io.ktor.routing.route
import jetbrains.exodus.database.TransientEntityStore
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.koin.ktor.ext.inject
import java.util.*

fun Route.index() = route("/") {
val store by inject<TransientEntityStore>()
val reporter by inject<StatisticsReporter>()

get {
call.respondTemplate("index", mapOf(
"title" to "dogbin"
))
call.respondTemplate(
"index", mapOf(
"title" to "dogbin"
)
)
}

get("/{slug}") {
@@ -42,10 +44,12 @@ fun Route.index() = route("/") {
} else {
if (doc.type == XdDocumentType.URL) {
runBlocking {
reporter.reportImpression(doc.slug, false, call.request)
reporter.reportEvent(Event.URL_REDIRECT, call.request)
call.respondRedirect(doc.stringContent!!, true)
}
} else {
documentDto = FrontendDocumentDto.fromDocument(doc, call.locale)
documentDto = FrontendDocumentDto.fromDocument(doc, reporter, call.locale)
if (call.session() != null) {
val usr = call.user(store)
editable = doc.userCanEdit(usr)
@@ -54,6 +58,7 @@ fun Route.index() = route("/") {
}
}
if (documentDto != null) {
reporter.reportImpression(documentDto!!.slug, true, call.request)
call.respondTemplate(
"index", mapOf(
"title" to documentDto!!.title,
@@ -75,14 +80,15 @@ fun Route.index() = route("/") {
call.respondRedirect("/")
}
} else {
documentDto = FrontendDocumentDto.fromDocument(doc, call.locale)
documentDto = FrontendDocumentDto.fromDocument(doc, reporter, call.locale)
if (call.session() != null) {
val usr = call.user(store)
editable = doc.userCanEdit(usr)
}
}
}
if (documentDto != null) {
reporter.reportImpression(documentDto!!.slug, true, call.request)
call.respondTemplate(
"index", mapOf(
"title" to documentDto!!.title,
@@ -104,7 +110,7 @@ fun Route.index() = route("/") {
call.respondRedirect("/")
}
} else {
documentDto = FrontendDocumentDto.fromDocument(doc, call.locale)
documentDto = FrontendDocumentDto.fromDocument(doc, reporter, call.locale)
if (call.session() != null) {
val usr = call.user(store)
canEdit = doc.userCanEdit(usr)

0 comments on commit 7b281ba

Please sign in to comment.
You can’t perform that action at this time.