aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarvin Borner2019-05-13 18:18:57 +0200
committerMarvin Borner2019-05-13 18:18:57 +0200
commitb9a392f5f1db5c7de60e929fdcc0ca42885f81ca (patch)
tree0f9aa014bcabfc3d7205898ada71f15d4490cb0a /src
parent72073df2c225f96889620e30c963dd807ca01a90 (diff)
Added user based dark theme support
Co-authored-by: LarsVomMars <lars@kroenner.eu>
Diffstat (limited to 'src')
-rw-r--r--src/main/kotlin/App.kt11
-rw-r--r--src/main/kotlin/DatabaseController.kt36
-rw-r--r--src/main/kotlin/FileController.kt9
-rw-r--r--src/main/kotlin/UserHandler.kt54
-rw-r--r--src/main/resources/css/darkLayout.css32
-rw-r--r--src/main/resources/css/index.css6
-rw-r--r--src/main/resources/js/index.js6
-rw-r--r--src/main/resources/views/admin.rocker.html5
-rw-r--r--src/main/resources/views/files.rocker.html5
-rw-r--r--src/main/resources/views/fileview.rocker.html5
-rw-r--r--src/main/resources/views/index.rocker.html17
-rw-r--r--src/main/resources/views/layout.rocker.html10
-rw-r--r--src/main/resources/views/login.rocker.html5
-rw-r--r--src/main/resources/views/register.rocker.html5
-rw-r--r--src/main/resources/views/setup.rocker.html5
15 files changed, 172 insertions, 39 deletions
diff --git a/src/main/kotlin/App.kt b/src/main/kotlin/App.kt
index df845a1..3607702 100644
--- a/src/main/kotlin/App.kt
+++ b/src/main/kotlin/App.kt
@@ -14,11 +14,11 @@ import java.util.logging.*
import kotlin.system.*
// TODO: Add abstract and secure file home support for windows/BSD/macOS
-val fileHome = if (System.getProperty("os.name") != "Linux") "files" else "/usr/share/kloud/files"
+const val debug = true
+val fileHome = if (System.getProperty("os.name") != "Linux" || debug) "files" else "/usr/share/kloud/files"
val databaseController = DatabaseController()
val userHandler = UserHandler()
val fileController = FileController()
-const val debug = false
private val log = Logger.getLogger("App.kt")
fun main(args: Array<String>) {
@@ -82,7 +82,7 @@ fun main(args: Array<String>) {
get("/", { ctx ->
ctx.render(
"index.rocker.html",
- model("username", databaseController.getUsername(userHandler.getVerifiedUserId(ctx)))
+ model("username", databaseController.getUsername(userHandler.getVerifiedUserId(ctx)), "ctx", ctx)
)
}, roles(Roles.GUEST, Roles.USER))
@@ -102,6 +102,11 @@ fun main(args: Array<String>) {
get("/user/logout", userHandler::logout, roles(Roles.USER))
/**
+ * Toggles the users theme
+ */
+ post("/user/theme", userHandler::toggleTheme, roles(Roles.USER))
+
+ /**
* Renders the registration page
*/
get("/user/register", userHandler::renderRegistration, roles(Roles.GUEST))
diff --git a/src/main/kotlin/DatabaseController.kt b/src/main/kotlin/DatabaseController.kt
index 24a8278..bdbdc18 100644
--- a/src/main/kotlin/DatabaseController.kt
+++ b/src/main/kotlin/DatabaseController.kt
@@ -35,6 +35,7 @@ class DatabaseController {
val username = varchar("username", 24).uniqueIndex()
val password = varchar("password", 64)
val verification = varchar("verification", 64).uniqueIndex()
+ val darkTheme = bool("darkTheme").default(false)
}
/**
@@ -161,13 +162,14 @@ class DatabaseController {
}
}
- if (error) ctx.render("admin.rocker.html", model("message", "User already exists!"))
+ if (error) ctx.render("admin.rocker.html", model("message", "User already exists!", "ctx", ctx))
else ctx.render(
"admin.rocker.html", model(
- "message", "http://${ctx.host()}/user/register?username=$usernameString&token=$tokenString"
+ "message", "http://${ctx.host()}/user/register?username=$usernameString&token=$tokenString",
+ "ctx", ctx
)
)
- } else ctx.render("admin.rocker.html", model("message", "Please only use alphabetical characters!"))
+ } else ctx.render("admin.rocker.html", model("message", "Please only use alphabetical characters!", "ctx", ctx))
}
/**
@@ -221,6 +223,34 @@ class DatabaseController {
}
/**
+ * Returns true when user uses dark theme
+ */
+ fun isDarkTheme(userId: Int): Boolean {
+ return transaction {
+ try {
+ UserData.select { UserData.id eq userId }.map { it[UserData.darkTheme] }[0]
+ } catch (_: Exception) {
+ false
+ }
+ }
+ }
+
+ /**
+ * Toggles the dark theme
+ */
+ fun toggleDarkTheme(userId: Int) {
+ return transaction {
+ try {
+ UserData.update({ (UserData.id eq userId) }) {
+ it[darkTheme] = !isDarkTheme(userId)
+ }
+ } catch (_: Exception) {
+ //
+ }
+ }
+ }
+
+ /**
* Returns the corresponding verification id using [usernameString]
*/
fun getVerificationId(usernameString: String): String {
diff --git a/src/main/kotlin/FileController.kt b/src/main/kotlin/FileController.kt
index 32c9369..d62b4b4 100644
--- a/src/main/kotlin/FileController.kt
+++ b/src/main/kotlin/FileController.kt
@@ -36,7 +36,8 @@ class FileController {
"files.rocker.html", model(
"files", files,
"path", (if (firstParam.firstOrNull() == '/') firstParam.drop(1) else firstParam),
- "isShared", false
+ "isShared", false,
+ "ctx", ctx
)
)
}
@@ -178,7 +179,8 @@ class FileController {
"files.rocker.html", model(
"files", files,
"path", (if (fileLocation.firstOrNull() == '/') fileLocation.drop(1) else fileLocation),
- "isShared", true
+ "isShared", true,
+ "ctx", ctx
)
)
}
@@ -216,7 +218,8 @@ class FileController {
Charsets.UTF_8
).joinToString(separator = "\n"),
"filename", File(filePath).name,
- "extension", File(filePath).extension
+ "extension", File(filePath).extension,
+ "ctx", ctx
)
)
}
diff --git a/src/main/kotlin/UserHandler.kt b/src/main/kotlin/UserHandler.kt
index 33f3f14..e9d0ada 100644
--- a/src/main/kotlin/UserHandler.kt
+++ b/src/main/kotlin/UserHandler.kt
@@ -14,7 +14,7 @@ class UserHandler {
*/
fun renderLogin(ctx: Context) {
if (userHandler.getVerifiedUserId(ctx) > 0 || !databaseController.isSetup()) ctx.redirect("/")
- else ctx.render("login.rocker.html", model("message", "", "counter", 0))
+ else ctx.render("login.rocker.html", model("message", "", "counter", 0, "ctx", ctx))
}
/**
@@ -54,7 +54,8 @@ class UserHandler {
model(
"message",
"Login failed!",
- "counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt()
+ "counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt(),
+ "ctx", ctx
)
)
}
@@ -65,7 +66,8 @@ class UserHandler {
model(
"message",
"Too many request.",
- "counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt()
+ "counter", if (nextThreshold / 60 > 60) 3600 else nextThreshold.toInt(),
+ "ctx", ctx
)
)
}
@@ -81,10 +83,19 @@ class UserHandler {
}
/**
+ * Toggles the users dark theme
+ */
+ fun toggleTheme(ctx: Context) {
+ databaseController.toggleDarkTheme(userHandler.getVerifiedUserId(ctx))
+ val dark = databaseController.isDarkTheme(userHandler.getVerifiedUserId(ctx))
+ ctx.json(mapOf("dark" to dark))
+ }
+
+ /**
* Renders the admin interface
*/
fun renderAdmin(ctx: Context) {
- ctx.render("admin.rocker.html", model("message", ""))
+ ctx.render("admin.rocker.html", model("message", "", "ctx", ctx))
}
/**
@@ -92,7 +103,7 @@ class UserHandler {
*/
fun renderSetup(ctx: Context) {
if (databaseController.isSetup()) ctx.redirect("/user/login")
- else ctx.render("setup.rocker.html", model("message", ""))
+ else ctx.render("setup.rocker.html", model("message", "", "ctx", ctx))
}
/**
@@ -105,21 +116,30 @@ class UserHandler {
val verifyPassword = ctx.formParam("verifyPassword").toString()
// TODO: Clean up ugly if statements in validation
- if (!username.matches("[a-zA-Z0-9]+".toRegex()) || username.length <= 3) {
+ if (username.matches("[a-zA-Z0-9]+".toRegex()) && username.length > 3) {
if (password == verifyPassword) {
if (password.length >= 8)
if (databaseController.createUser(username, password, "ADMIN")) {
databaseController.toggleSetup()
ctx.redirect("/user/login")
- } else ctx.status(400).render("setup.rocker.html", model("message", "User already exists!"))
- else ctx.status(400).render("setup.rocker.html", model("message", "Password is too short!"))
- } else ctx.status(400).render("setup.rocker.html", model("message", "Passwords do not match!"))
+ } else ctx.status(400).render(
+ "setup.rocker.html",
+ model("message", "User already exists!", "ctx", ctx)
+ )
+ else ctx.status(400).render(
+ "setup.rocker.html",
+ model("message", "Password is too short!", "ctx", ctx)
+ )
+ } else ctx.status(400).render(
+ "setup.rocker.html",
+ model("message", "Passwords do not match!", "ctx", ctx)
+ )
} else ctx.status(400).render(
"setup.rocker.html",
- model("message", "Username must only use alphabetical characters!")
+ model("message", "Username must only use alphabetical characters!", "ctx", ctx)
)
} catch (err: Exception) {
- ctx.status(400).render("setup.rocker.html", model("message", "An error occurred!"))
+ ctx.status(400).render("setup.rocker.html", model("message", "An error occurred!", "ctx", ctx))
error(err)
}
}
@@ -135,7 +155,10 @@ class UserHandler {
else if (token.isNullOrEmpty()) throw ForbiddenResponse("Please provide a valid token!")
else {
if (databaseController.isUserRegistrationValid(username, token))
- ctx.render("register.rocker.html", model("username", username, "token", token, "message", ""))
+ ctx.render(
+ "register.rocker.html",
+ model("username", username, "token", token, "message", "", "ctx", ctx)
+ )
else ctx.redirect("/user/login")
}
}
@@ -158,19 +181,20 @@ class UserHandler {
ctx.redirect("/user/login")
} else ctx.render(
"register.rocker.html",
- model("username", username, "token", token, "message", "Not authorized!")
+ model("username", username, "token", token, "message", "Not authorized!", "ctx", ctx)
)
else ctx.render(
"register.rocker.html",
model(
"username", username,
"token", token,
- "message", "Please make sure that your password is at least 8 digits long!"
+ "message", "Please make sure that your password is at least 8 digits long!",
+ "ctx", ctx
)
)
} else ctx.render(
"register.rocker.html",
- model("username", username, "token", token, "message", "The passwords don't match!")
+ model("username", username, "token", token, "message", "The passwords don't match!", "ctx", ctx)
)
} catch (err: Exception) {
throw BadRequestResponse()
diff --git a/src/main/resources/css/darkLayout.css b/src/main/resources/css/darkLayout.css
new file mode 100644
index 0000000..71172a5
--- /dev/null
+++ b/src/main/resources/css/darkLayout.css
@@ -0,0 +1,32 @@
+/**
+ Main
+ */
+body {
+ background-color: #181a1b;
+}
+
+.main {
+ color: #d0cdc6
+}
+
+button {
+ text-decoration-color: initial;
+ background-color: #3d4043;
+ border-top-color: #595959;
+ border-right-color: #595959;
+ border-bottom-color: #595959;
+ border-left-color: #595959;
+ color: #ffffff;
+}
+
+input {
+ border-color: #575757;
+ color: #e8e6e3;
+}
+
+/**
+ Other stuff
+ */
+tr:hover {
+ background-color: #121516 !important;
+}
diff --git a/src/main/resources/css/index.css b/src/main/resources/css/index.css
new file mode 100644
index 0000000..5cf3c78
--- /dev/null
+++ b/src/main/resources/css/index.css
@@ -0,0 +1,6 @@
+.toggle {
+ position: absolute;
+ margin: 20px;
+ right: 0;
+ top: 0;
+}
diff --git a/src/main/resources/js/index.js b/src/main/resources/js/index.js
new file mode 100644
index 0000000..4939622
--- /dev/null
+++ b/src/main/resources/js/index.js
@@ -0,0 +1,6 @@
+document.querySelector("#toggle").addEventListener("click", () => {
+ const request = new XMLHttpRequest();
+ request.open("POST", "/user/theme");
+ request.onload = () => location.reload();
+ request.send();
+});
diff --git a/src/main/resources/views/admin.rocker.html b/src/main/resources/views/admin.rocker.html
index 26859eb..7bd25a9 100644
--- a/src/main/resources/views/admin.rocker.html
+++ b/src/main/resources/views/admin.rocker.html
@@ -1,6 +1,7 @@
-@args (String message)
+@import io.javalin.*
+@args (String message, Context ctx)
-@layout.template("Index", RockerContent.NONE, RockerContent.NONE) -> {
+@layout.template("Index", ctx, RockerContent.NONE, RockerContent.NONE) -> {
<div class="flex">
<div>
<h1>Add new user</h1>
diff --git a/src/main/resources/views/files.rocker.html b/src/main/resources/views/files.rocker.html
index 43a3488..8e75ac2 100644
--- a/src/main/resources/views/files.rocker.html
+++ b/src/main/resources/views/files.rocker.html
@@ -1,5 +1,6 @@
@import java.util.ArrayList
-@args (ArrayList files, String path, Boolean isShared)
+@import io.javalin.*
+@args (ArrayList files, String path, Boolean isShared, Context ctx)
@css => {
<link href="/css/files.css" rel="stylesheet">
@@ -14,7 +15,7 @@
<script src="/js/files.js"></script>
}
-@layout.template(files.size() + " Files", css, js) -> {
+@layout.template(files.size() + " Files", ctx, css, js) -> {
<div class="drop" id="drop">
<h2 class="navigation">
<i class="icon ion-md-home"></i>
diff --git a/src/main/resources/views/fileview.rocker.html b/src/main/resources/views/fileview.rocker.html
index c1fdff8..b3f8341 100644
--- a/src/main/resources/views/fileview.rocker.html
+++ b/src/main/resources/views/fileview.rocker.html
@@ -1,4 +1,5 @@
-@args (String content, String filename, String extension)
+@import io.javalin.*
+@args (String content, String filename, String extension, Context ctx)
@css => {
<link href="/css/fileview.css" rel="stylesheet">
@@ -12,7 +13,7 @@
<script src="/js/fileview.js"></script>
}
-@layout.template("File " + filename, css, js) -> {
+@layout.template("File " + filename, ctx, css, js) -> {
<button class="switch" id="raw">Show raw</button>
<span class="settings" id="settings">
<label for="code">Linecount</label><input id="code" type="checkbox">
diff --git a/src/main/resources/views/index.rocker.html b/src/main/resources/views/index.rocker.html
index cc18d3b..2e1b9dd 100644
--- a/src/main/resources/views/index.rocker.html
+++ b/src/main/resources/views/index.rocker.html
@@ -1,9 +1,22 @@
@import space.anity.DatabaseController
@import space.anity.UserHandler
-@args (String username)
+@import io.javalin.*
+@args (String username, Context ctx)
-@layout.template("Index", RockerContent.NONE, RockerContent.NONE) -> {
+@css => {
+<link href="/css/index.css" rel="stylesheet">
+}
+
+@js => {
+<script src="/js/index.js"></script>
+}
+
+@layout.template("Index", ctx, css, js) -> {
<div class="flex">
+ @if (username.length() > 0) {
+ <button class="toggle" id="toggle">Dark theme</button>
+ }
+
<h1>Welcome to Kloud<span class="username">@(username == "" ? "" : " " + username)</span>!</h1>
<div>
diff --git a/src/main/resources/views/layout.rocker.html b/src/main/resources/views/layout.rocker.html
index 3e3fb5e..9963aad 100644
--- a/src/main/resources/views/layout.rocker.html
+++ b/src/main/resources/views/layout.rocker.html
@@ -1,4 +1,7 @@
-@args (String title, RockerContent css, RockerContent js, RockerBody content)
+@import space.anity.DatabaseController
+@import space.anity.UserHandler
+@import io.javalin.*
+@args (String title, Context ctx, RockerContent css, RockerContent js, RockerBody content)
<!doctype html>
<html lang="en">
@@ -10,6 +13,11 @@
<link href="/css/icons.css" rel="stylesheet">
<link href="/css/layout.css" rel="stylesheet">
@css
+
+ @if((new DatabaseController()).isDarkTheme((new UserHandler()).getVerifiedUserId(ctx))) {
+ <link href="/css/darkLayout.css" rel="stylesheet">
+ }
+
<title>@title</title>
</head>
<body>
diff --git a/src/main/resources/views/login.rocker.html b/src/main/resources/views/login.rocker.html
index a8b06be..1e2adc4 100644
--- a/src/main/resources/views/login.rocker.html
+++ b/src/main/resources/views/login.rocker.html
@@ -1,11 +1,12 @@
-@args (String message, Integer counter)
+@import io.javalin.*
+@args (String message, Integer counter, Context ctx)
@js => {
<script>const counter = @counter;</script>
<script src="/js/login.js"></script>
}
-@layout.template("Login", RockerContent.NONE, js) -> {
+@layout.template("Login", ctx, RockerContent.NONE, js) -> {
<div class="flex">
<h1>Login</h1>
diff --git a/src/main/resources/views/register.rocker.html b/src/main/resources/views/register.rocker.html
index b86c2e0..8516561 100644
--- a/src/main/resources/views/register.rocker.html
+++ b/src/main/resources/views/register.rocker.html
@@ -1,6 +1,7 @@
-@args (String username, String token, String message)
+@import io.javalin.*
+@args (String username, String token, String message, Context ctx)
-@layout.template("Register", RockerContent.NONE, RockerContent.NONE) -> {
+@layout.template("Register", ctx, RockerContent.NONE, RockerContent.NONE) -> {
<div class="flex">
<h1>Register</h1>
diff --git a/src/main/resources/views/setup.rocker.html b/src/main/resources/views/setup.rocker.html
index 595f84a..3601817 100644
--- a/src/main/resources/views/setup.rocker.html
+++ b/src/main/resources/views/setup.rocker.html
@@ -1,6 +1,7 @@
-@args (String message)
+@import io.javalin.*
+@args (String message, Context ctx)
-@layout.template("Setup", RockerContent.NONE, RockerContent.NONE) -> {
+@layout.template("Setup", ctx, RockerContent.NONE, RockerContent.NONE) -> {
<div class="flex">
<h1>Setup</h1>