Skip to content
This repository was archived by the owner on Jul 13, 2021. It is now read-only.

Commit 1833aab

Browse files
committed
Initial commit of full-stack demo app
0 parents  commit 1833aab

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1594
-0
lines changed

.gitignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
backend/.database/*
2+
!backend/.database/person-data.json
3+
!backend/.database/team-data.json
4+
!backend/.database/places-data.json
5+
.idea/*
6+
!.idea/runConfigurations
7+
!.idea/runConfigurations/*
8+
!.idea/vcs.xml
9+
build
10+
*.iml
11+
12+
*.versionsBackup
13+
*.releaseBackup
14+
release.properties
15+
local.properties
16+
17+
node_modules
18+
npm-debug.log

.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/build.gradle

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
group = 'org.jetbrains.demo.thinkter'
2+
version = '0.0.1-SNAPSHOT'
3+
4+
apply plugin: 'java'
5+
apply plugin: 'kotlin'
6+
apply plugin: 'org.jetbrains.kotlin.frontend'
7+
8+
dependencies {
9+
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
10+
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
11+
12+
compile "org.jetbrains.ktor:ktor-locations:$ktor_version"
13+
compile "org.jetbrains.ktor:ktor-html-builder:$ktor_version"
14+
compile "org.ehcache:ehcache:3.0.0.m4"
15+
16+
compile "org.jetbrains.squash:squash-h2:$squash_version"
17+
18+
19+
testCompile("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
20+
testCompile "org.jetbrains.ktor:ktor-test-host:$ktor_version"
21+
testCompile "org.jsoup:jsoup:1.9.1"
22+
23+
compile "org.jetbrains.ktor:ktor-jetty:$ktor_version"
24+
}
25+
26+
27+
ktor {
28+
port = 9090
29+
jvmOptions = ["-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5009"]
30+
}
31+
32+
33+
sourceSets {
34+
main.java.srcDirs += "src"
35+
main.resources.srcDirs += "resources"
36+
main.kotlin.srcDirs += "src"
37+
test.java.srcDirs += "test"
38+
test.kotlin.srcDirs += "test"
39+
test.resources.srcDirs += "resources"
40+
}

backend/resources/application.conf

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
ktor {
2+
deployment {
3+
port = 9090
4+
environment = development
5+
autoreload = true
6+
watch = [ thinkter ]
7+
}
8+
9+
application {
10+
id = Thinkter
11+
modules = [org.jetbrains.demo.thinkter.ApplicationKt.main]
12+
}
13+
}
14+
15+
database {
16+
storage = ".database"
17+
logsql = true
18+
}

backend/resources/logback.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<configuration>
2+
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
3+
<encoder>
4+
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
5+
</encoder>
6+
</appender>
7+
8+
<root level="trace">
9+
<appender-ref ref="STDOUT"/>
10+
</root>
11+
12+
<logger name="org.eclipse.jetty" level="INFO"/>
13+
<logger name="io.netty" level="INFO"/>
14+
15+
<logger name="Elemental.Loader" level="INFO"/>
16+
17+
</configuration>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package org.jetbrains.demo.thinkter
2+
3+
import org.jetbrains.demo.thinkter.dao.*
4+
import org.jetbrains.ktor.application.*
5+
import org.jetbrains.ktor.features.*
6+
import org.jetbrains.ktor.http.*
7+
import org.jetbrains.ktor.locations.*
8+
import org.jetbrains.ktor.logging.*
9+
import org.jetbrains.ktor.routing.*
10+
import org.jetbrains.ktor.sessions.*
11+
import java.io.*
12+
13+
data class Session(val userId: String)
14+
15+
fun Application.main() {
16+
val dir = File("target/db")
17+
val database = ThinkterDatabase(/*JDBCConnection.Companion.create(H2Dialect, pool)*/)
18+
val storage: ThinkterStorage = ThinkterCache(database, File(dir.parentFile, "ehcache"))
19+
20+
install(DefaultHeaders)
21+
install(CallLogging)
22+
install(ConditionalHeaders)
23+
install(PartialContentSupport)
24+
install(Locations)
25+
install(StatusPages) {
26+
exception<NotImplementedError> { call.respond(HttpStatusCode.NotImplemented) }
27+
}
28+
29+
withSessions<Session> {
30+
withCookieByValue {
31+
settings = SessionCookiesSettings(transformers = listOf(SessionCookieTransformerMessageAuthentication(hashKey)))
32+
}
33+
}
34+
35+
routing {
36+
index(storage)
37+
postThought(storage, ::hash)
38+
delete(storage, ::hash)
39+
userPage(storage)
40+
viewThought(storage, ::hash)
41+
42+
login(storage, ::hash)
43+
register(storage, ::hash)
44+
}
45+
}
46+
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.jetbrains.demo.thinkter
2+
3+
import kotlinx.html.*
4+
import org.jetbrains.ktor.html.*
5+
6+
class ApplicationPage : Template<HTML> {
7+
val caption = Placeholder<TITLE>()
8+
val head = Placeholder<HEAD>()
9+
10+
override fun HTML.apply() {
11+
head {
12+
title {
13+
insert(caption)
14+
}
15+
insert(head)
16+
meta {
17+
name = "viewport"
18+
content = "width=device-width, initial-scale=1.0"
19+
}
20+
}
21+
body {
22+
div {
23+
id = "content"
24+
}
25+
script(src = "frontend/frontend.bundle.js")
26+
}
27+
}
28+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.jetbrains.demo.thinkter
2+
3+
import org.jetbrains.demo.thinkter.dao.*
4+
import org.jetbrains.ktor.application.*
5+
import org.jetbrains.ktor.locations.*
6+
import org.jetbrains.ktor.routing.*
7+
import org.jetbrains.ktor.sessions.*
8+
9+
fun Route.delete(dao: ThinkterStorage, hashFunction: (String) -> String) {
10+
post<ThoughtDelete> {
11+
val user = call.sessionOrNull<Session>()?.let { dao.user(it.userId) }
12+
val thought = dao.getThought(it.id)
13+
14+
if (user == null || thought.userId != user.userId || !call.verifyCode(it.date, user, it.code, hashFunction)) {
15+
call.redirect(ViewThought(it.id))
16+
} else {
17+
dao.deleteThought(it.id)
18+
call.redirect(Index())
19+
}
20+
}
21+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.jetbrains.demo.thinkter
2+
3+
import org.jetbrains.demo.thinkter.dao.*
4+
import org.jetbrains.ktor.application.*
5+
import org.jetbrains.ktor.html.*
6+
import org.jetbrains.ktor.http.*
7+
import org.jetbrains.ktor.locations.*
8+
import org.jetbrains.ktor.routing.*
9+
import org.jetbrains.ktor.sessions.*
10+
11+
fun Route.index(storage: ThinkterStorage) {
12+
contentType(ContentType.Text.Html) {
13+
get<Index> {
14+
call.respondHtmlTemplate(ApplicationPage()) {
15+
caption { +"Thinkter" }
16+
}
17+
}
18+
}
19+
contentType(ContentType.Application.Json) {
20+
get<Index> {
21+
val user = call.sessionOrNull<Session>()?.let { storage.user(it.userId) }
22+
val top = storage.top(10).map { storage.getThought(it) }
23+
val latest = storage.latest(10).map { storage.getThought(it) }
24+
val etagString = user?.userId + "," + top.joinToString { it.id.toString() } + latest.joinToString { it.id.toString() }
25+
val etag = etagString.hashCode()
26+
}
27+
}
28+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.jetbrains.demo.thinkter
2+
3+
import org.jetbrains.ktor.locations.*
4+
5+
6+
@location("/")
7+
class Index()
8+
9+
@location("/post-new")
10+
data class PostThought(val text: String = "", val date: Long = 0L, val code: String = "")
11+
12+
@location("/thought/{id}/delete")
13+
data class ThoughtDelete(val id: Int, val date: Long, val code: String)
14+
15+
@location("/thought/{id}")
16+
data class ViewThought(val id: Int)
17+
18+
@location("/user/{user}")
19+
data class UserPage(val user: String)
20+
21+
@location("/register")
22+
data class Register(val userId: String = "", val displayName: String = "", val email: String = "", val password: String = "", val error: String = "")
23+
24+
@location("/login")
25+
data class Login(val userId: String = "", val password: String = "", val error: String = "")
26+
27+
@location("/logout")
28+
class Logout()

0 commit comments

Comments
 (0)