diff options
author | Marvin Borner | 2019-04-16 14:57:33 +0200 |
---|---|---|
committer | Marvin Borner | 2019-04-16 14:57:33 +0200 |
commit | a32ec653bf2acc777d64803189a03a4b07b24096 (patch) | |
tree | 25f199a5b15df8d333434e40a49d73f5274b6a10 | |
parent | 0177a6d90f3310d81eda66193ee4f4832b6e4bbd (diff) |
Added file sharing feature
-rw-r--r-- | src/main/kotlin/App.kt | 46 | ||||
-rw-r--r-- | src/main/kotlin/DatabaseController.kt | 34 | ||||
-rw-r--r-- | src/main/resources/css/files.css | 21 | ||||
-rw-r--r-- | src/main/resources/fonts/ionicons .eot | bin | 0 -> 112662 bytes | |||
-rw-r--r-- | src/main/resources/js/files.js | 31 | ||||
-rw-r--r-- | src/main/resources/js/fileview.js | 5 | ||||
-rw-r--r-- | src/main/resources/views/files.rocker.html | 5 | ||||
-rw-r--r-- | src/main/resources/views/index.rocker.html | 12 |
8 files changed, 147 insertions, 7 deletions
diff --git a/src/main/kotlin/App.kt b/src/main/kotlin/App.kt index dd1cfb4..4572cf1 100644 --- a/src/main/kotlin/App.kt +++ b/src/main/kotlin/App.kt @@ -107,6 +107,16 @@ fun main() { * Deletes file */ post("/delete/*", ::delete, roles(Roles.USER)) + + /** + * Shares file + */ + post("/share/*", ::shareFile, roles(Roles.USER)) + + /** + * Shows the shared file + */ + get("/shared", ::renderSharedFile, roles(Roles.GUEST)) } } @@ -334,6 +344,42 @@ fun delete(ctx: Context) { } /** + * Shares the requested file via the accessId + */ +fun shareFile(ctx: Context) { + val userId = getVerifiedUserId(ctx) + if (userId > 0) { + val accessId = databaseController.getAccessId(ctx.splats()[0], userId) + ctx.result("${ctx.host()}/shared?id=$accessId") + } +} + +/** + * Renders the shared file + */ +fun renderSharedFile(ctx: Context) { + val accessId = ctx.queryParam("id").toString() + val sharedFileData = databaseController.getSharedFile(accessId) + if (sharedFileData.first > 0 && sharedFileData.second.isNotEmpty()) { + val sharedFileLocation = "$fileHome/${sharedFileData.first}/${sharedFileData.second}" + if (isHumanReadable(File(sharedFileLocation))) { + ctx.render( + "fileview.rocker.html", model( + "content", Files.readAllLines( + Paths.get(sharedFileLocation), + Charsets.UTF_8 + ).joinToString(separator = "\n"), + "filename", File(sharedFileLocation).name, + "extension", File(sharedFileLocation).extension + ) + ) + } else ctx.result(FileInputStream(File(sharedFileLocation))) + } else { + log.info("Unknown file!") + } +} + +/** * Declares the roles in which a user can be in */ enum class Roles : Role { diff --git a/src/main/kotlin/DatabaseController.kt b/src/main/kotlin/DatabaseController.kt index 088f342..7b229f4 100644 --- a/src/main/kotlin/DatabaseController.kt +++ b/src/main/kotlin/DatabaseController.kt @@ -19,6 +19,7 @@ class DatabaseController(dbFileLocation: String = "main.db") { val path = text("path").uniqueIndex() val userId = integer("userId").references(UserData.id) val accessId = varchar("accessId", 64).uniqueIndex() // TODO: Add file sharing + val isShared = bool("isShared").default(false) } /** @@ -237,6 +238,39 @@ class DatabaseController(dbFileLocation: String = "main.db") { } /** + * Returns the accessId of the given File + */ + fun getAccessId(fileLocation: String, userId: Int): String { + return transaction { + try { + FileLocation.update({ (FileLocation.userId eq userId) and (FileLocation.path eq fileLocation) }) { + it[isShared] = true + } + FileLocation.select { (FileLocation.path eq fileLocation) and (FileLocation.userId eq userId) }.map { it[FileLocation.accessId] }[0] + } catch (_: Exception) { + "" + } + } + } + + /** + * Gets the shared file via [accessId] + */ + fun getSharedFile(accessId: String): Pair<Int, String> { + return transaction { + try { + if (FileLocation.select { FileLocation.accessId eq accessId }.map { it[FileLocation.isShared] }[0]) + FileLocation.select { FileLocation.accessId eq accessId }.map { it[FileLocation.userId] to it[FileLocation.path] }[0] + else + Pair(-1, "") + } catch (_: org.jetbrains.exposed.exceptions.ExposedSQLException) { + log.warning("File does not exist!") + Pair(-1, "") + } + } + } + + /** * Checks whether the site has been set up */ fun isSetup(): Boolean { diff --git a/src/main/resources/css/files.css b/src/main/resources/css/files.css index 3ceb173..c7302bf 100644 --- a/src/main/resources/css/files.css +++ b/src/main/resources/css/files.css @@ -45,11 +45,15 @@ colgroup col:nth-child(2) { } colgroup col:nth-child(3) { - width: 30%; + width: 25%; } colgroup col:nth-child(4) { - width: 15%; + width: 10%; +} + +colgroup col:nth-child(5) { + width: 10%; } .drop { @@ -70,3 +74,16 @@ colgroup col:nth-child(4) { transform: scale(1.3); color: red; } + +.share { + font-size: 20px; + background-color: inherit; + border: 0; + z-index: 100; + cursor: pointer; +} + +.share:hover { + transform: scale(1.3); + color: dodgerblue; +} diff --git a/src/main/resources/fonts/ionicons .eot b/src/main/resources/fonts/ionicons .eot Binary files differnew file mode 100644 index 0000000..671df91 --- /dev/null +++ b/src/main/resources/fonts/ionicons .eot diff --git a/src/main/resources/js/files.js b/src/main/resources/js/files.js index 8b8bd87..f776165 100644 --- a/src/main/resources/js/files.js +++ b/src/main/resources/js/files.js @@ -33,7 +33,8 @@ drop.addEventListener('drop', e => { row.insertCell(0).innerHTML = file.name; row.insertCell(1).innerHTML = bytesToSize(file.size); row.insertCell(2).innerHTML = `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}`; - row.insertCell(3).innerHTML = "<td><button class='delete'><i class='icon ion-md-trash'></i></button></td>"; + row.insertCell(3).innerHTML = "<td><button class='share'><i class='icon ion-md-share'></i></button></td>"; + row.insertCell(4).innerHTML = "<td><button class='delete'><i class='icon ion-md-trash'></i></button></td>"; setListeners(); @@ -128,6 +129,34 @@ function setListeners() { parent.remove(); }) }); + + // share button + document.querySelectorAll(".share").forEach(element => { + element.addEventListener("click", e => { + e.stopPropagation(); + const request = new XMLHttpRequest(); + const parent = e.target.closest("tr"); + const fileName = parent.getAttribute("data-href") || parent.getAttribute("data-path"); + + request.open("POST", `/share/${path}/${fileName}`); + request.onload = () => { + if (request.readyState === 4) { + if (request.status === 200) { + const input = document.createElement('input'); + input.setAttribute('value', request.responseText); + document.body.appendChild(input); + input.select(); + document.execCommand('copy'); + document.body.removeChild(input); + alert("Copied url to clipboard!") + } else { + alert("Something went wrong."); + } + } + }; + request.send(); + }) + }); } setListeners(); diff --git a/src/main/resources/js/fileview.js b/src/main/resources/js/fileview.js index ace7884..d78c342 100644 --- a/src/main/resources/js/fileview.js +++ b/src/main/resources/js/fileview.js @@ -1,6 +1,7 @@ const preview = document.getElementById("preview"); const content = document.getElementById("content"); -const body = document.getElementsByTagName("body")[0]; +const html = document.getElementsByTagName("html")[0]; +const body = document.body; // buttons const raw = document.getElementById("raw"); @@ -23,12 +24,14 @@ if (extension === "md" || extension === "html") { raw.addEventListener("click", () => { if (preview.style.display === "block") { + html.style.overflow = "visible"; body.style.overflow = "visible"; raw.innerText = "Show preview"; preview.style.display = "none"; content.style.display = "block"; settings.style.display = "block"; } else { + html.style.overflow = "hidden"; body.style.overflow = "hidden"; raw.innerText = "Show raw"; preview.style.display = "block"; diff --git a/src/main/resources/views/files.rocker.html b/src/main/resources/views/files.rocker.html index acbe812..0e42891 100644 --- a/src/main/resources/views/files.rocker.html +++ b/src/main/resources/views/files.rocker.html @@ -35,6 +35,7 @@ <th data-asc="true">Name</th> <th data-asc="true">Size</th> <th data-asc="true">Last modified</th> + <th data-asc="true">Share</th> <th data-asc="true">Delete</th> </tr> <tr data-href="../"> @@ -42,6 +43,7 @@ <td></td> <td></td> <td></td> + <td></td> </tr> </thead> @@ -56,6 +58,9 @@ <td data-size="@fileArray[4]">@fileArray[1]</td> <td data-date="@fileArray[5]">@fileArray[2]</td> <td> + <button class="share"><i class="icon ion-md-share"></i></button> + </td> + <td> <button class="delete"><i class="icon ion-md-trash"></i></button> </td> </tr> diff --git a/src/main/resources/views/index.rocker.html b/src/main/resources/views/index.rocker.html index 4f5d32b..a0b4035 100644 --- a/src/main/resources/views/index.rocker.html +++ b/src/main/resources/views/index.rocker.html @@ -4,10 +4,16 @@ <h1>Welcome to Kloud <i>@username</i>!</h1> @if(username.length() > 0) { -<button><a href="/logout/">Logout</a></button> +<a href="/logout"> + <button>Logout</button> +</a> } else { -<button><a href="/login/">Login</a></button> +<a href="/login"> + <button>Login</button> +</a> } -<button><a href="/files/">Files</a></button> +<a href="/files/"> + <button>Files</button> +</a> } |