Replace create reply ajax page with Kotlin version
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Mon, 24 Jul 2017 17:31:29 +0000 (19:31 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Mon, 24 Jul 2017 17:31:40 +0000 (19:31 +0200)
src/main/java/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.java [deleted file]
src/main/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.kt [new file with mode: 0644]
src/test/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPageTest.kt [new file with mode: 0644]
src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt

diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.java
deleted file mode 100644 (file)
index fe2ae85..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Sone - CreateReplyAjaxPage.java - Copyright © 2010–2016 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.web.ajax;
-
-import com.google.common.base.Optional;
-
-import net.pterodactylus.sone.data.Post;
-import net.pterodactylus.sone.data.PostReply;
-import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.text.TextFilter;
-import net.pterodactylus.sone.web.WebInterface;
-import net.pterodactylus.sone.web.page.FreenetRequest;
-
-/**
- * This AJAX page create a reply.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class CreateReplyAjaxPage extends JsonPage {
-
-       /**
-        * Creates a new “create reply” AJAX page.
-        *
-        * @param webInterface
-        *            The Sone web interface
-        */
-       public CreateReplyAjaxPage(WebInterface webInterface) {
-               super("createReply.ajax", webInterface);
-       }
-
-       //
-       // JSONPAGE METHODS
-       //
-
-       /**
-        * {@inheritDoc}
-        */
-       @Override
-       protected JsonReturnObject createJsonObject(FreenetRequest request) {
-               String postId = request.getHttpRequest().getParam("post");
-               String text = request.getHttpRequest().getParam("text").trim();
-               String senderId = request.getHttpRequest().getParam("sender");
-               Sone sender = webInterface.getCore().getLocalSone(senderId);
-               if (sender == null) {
-                       sender = getCurrentSone(request.getToadletContext());
-               }
-               Optional<Post> post = webInterface.getCore().getPost(postId);
-               if (!post.isPresent()) {
-                       return createErrorJsonObject("invalid-post-id");
-               }
-               text = TextFilter.filter(request.getHttpRequest().getHeader("host"), text);
-               PostReply reply = webInterface.getCore().createReply(sender, post.get(), text);
-               return createSuccessJsonObject().put("reply", reply.getId()).put("sone", sender.getId());
-       }
-
-}
diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.kt
new file mode 100644 (file)
index 0000000..7cf2e1e
--- /dev/null
@@ -0,0 +1,30 @@
+package net.pterodactylus.sone.web.ajax
+
+import net.pterodactylus.sone.text.TextFilter
+import net.pterodactylus.sone.utils.emptyToNull
+import net.pterodactylus.sone.utils.headers
+import net.pterodactylus.sone.utils.let
+import net.pterodactylus.sone.utils.parameters
+import net.pterodactylus.sone.web.WebInterface
+import net.pterodactylus.sone.web.page.FreenetRequest
+
+/**
+ * This AJAX page create a reply.
+ */
+class CreateReplyAjaxPage(webInterface: WebInterface) : JsonPage("createReply.ajax", webInterface) {
+
+       override fun createJsonObject(request: FreenetRequest): JsonReturnObject =
+                       request.parameters["post"].emptyToNull
+                                       ?.let(webInterface.core::getPost)
+                                       ?.let { post ->
+                                               val text = TextFilter.filter(request.headers["Host"], request.parameters["text"])
+                                               val sender = request.parameters["sender"].let(webInterface.core::getLocalSone) ?: getCurrentSone(request.toadletContext)
+                                               val reply = webInterface.core.createReply(sender, post, text)
+                                               createSuccessJsonObject().apply {
+                                                       put("reply", reply.id)
+                                                       put("sone", sender.id)
+                                               }
+                                       }
+                                       ?: createErrorJsonObject("invalid-post-id")
+
+}
diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPageTest.kt
new file mode 100644 (file)
index 0000000..9d9008b
--- /dev/null
@@ -0,0 +1,80 @@
+package net.pterodactylus.sone.web.ajax
+
+import net.pterodactylus.sone.data.Post
+import net.pterodactylus.sone.data.PostReply
+import net.pterodactylus.sone.data.Sone
+import net.pterodactylus.sone.test.mock
+import net.pterodactylus.sone.test.whenever
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.equalTo
+import org.junit.Test
+
+/**
+ * Unit test for [CreateReplyAjaxPage].
+ */
+class CreateReplyAjaxPageTest : JsonPageTest(::CreateReplyAjaxPage) {
+
+       @Test
+       fun `page returns correct path`() {
+               assertThat(page.path, equalTo("createReply.ajax"))
+       }
+
+       @Test
+       fun `page needs form password`() {
+               assertThat(page.needsFormPassword(), equalTo(true))
+       }
+
+       @Test
+       fun `page requires login`() {
+               assertThat(page.requiresLogin(), equalTo(true))
+       }
+
+       @Test
+       fun `invalid post ID results in error message`() {
+           assertThat(json.isSuccess, equalTo(false))
+               assertThat(json.error, equalTo("invalid-post-id"))
+       }
+
+       @Test
+       fun `valid post ID results in created reply`() {
+               val post = mock<Post>()
+               addPost("post-id", post)
+               val reply = mock<PostReply>().apply { whenever(id).thenReturn("reply-id") }
+               whenever(core.createReply(currentSone, post, "")).thenReturn(reply)
+           addRequestParameter("post", "post-id")
+               assertThat(json.isSuccess, equalTo(true))
+               assertThat(json["reply"].asText(), equalTo("reply-id"))
+               assertThat(json["sone"].asText(), equalTo("soneId"))
+       }
+
+       @Test
+       fun `text is filtered when creating reply`() {
+               val post = mock<Post>()
+               addPost("post-id", post)
+               val reply = mock<PostReply>().apply { whenever(id).thenReturn("reply-id") }
+               whenever(core.createReply(currentSone, post, "Text with KSK@foo.bar link")).thenReturn(reply)
+               addRequestParameter("post", "post-id")
+               addRequestParameter("text", "Text with http://127.0.0.1:8888/KSK@foo.bar link")
+               addRequestHeader("Host", "127.0.0.1:8888")
+               assertThat(json.isSuccess, equalTo(true))
+               assertThat(json["reply"].asText(), equalTo("reply-id"))
+               assertThat(json["sone"].asText(), equalTo("soneId"))
+       }
+
+       @Test
+       fun `sender can be chosen from local sones`() {
+           val sone = mock<Sone>().apply { whenever(id).thenReturn("local-sone") }
+               addLocalSone("local-sone", sone)
+               val post = mock<Post>()
+               addPost("post-id", post)
+               val reply = mock<PostReply>().apply { whenever(id).thenReturn("reply-id") }
+               whenever(core.createReply(sone, post, "Text")).thenReturn(reply)
+               addRequestParameter("post", "post-id")
+               addRequestParameter("text", "Text")
+               addRequestParameter("sender", "local-sone")
+               assertThat(json.isSuccess, equalTo(true))
+               assertThat(json["reply"].asText(), equalTo("reply-id"))
+               assertThat(json["sone"].asText(), equalTo("local-sone"))
+       }
+
+}
index b0a67d4..87b2939 100644 (file)
@@ -50,6 +50,7 @@ open class JsonPageTest(pageSupplier: (WebInterface) -> JsonPage = { _ -> mock<J
        private val requestParts = mutableMapOf<String, String>()
        private val localSones = mutableMapOf<String, Sone>()
        private val remoteSones = mutableMapOf<String, Sone>()
+       private val posts = mutableMapOf<String, Post>()
        private val newPosts = mutableMapOf<String, Post>()
        private val newReplies = mutableMapOf<String, PostReply>()
        private val linkedElements = mutableMapOf<String, LinkedElement>()
@@ -69,7 +70,8 @@ open class JsonPageTest(pageSupplier: (WebInterface) -> JsonPage = { _ -> mock<J
        @Before
        fun setupCore() {
                whenever(core.getSone(anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() }
-               whenever(core.getPost(anyString())).thenAnswer { newPosts[it[0]].asOptional() }
+               whenever(core.getLocalSone(anyString())).thenAnswer { localSones[it[0]] }
+               whenever(core.getPost(anyString())).thenAnswer { (posts + newPosts)[it[0]].asOptional() }
        }
 
        @Before
@@ -143,6 +145,14 @@ open class JsonPageTest(pageSupplier: (WebInterface) -> JsonPage = { _ -> mock<J
                remoteSones += sone.id to sone
        }
 
+       protected fun addLocalSone(id: String, sone: Sone) {
+               localSones += id to sone
+       }
+
+       protected fun addPost(id: String, post: Post) {
+               posts[id] = post
+       }
+
        protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) =
                        mock<Post>().apply {
                                whenever(this.id).thenReturn(id)