+++ /dev/null
-/*
- * 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());
- }
-
-}
--- /dev/null
+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")
+
+}
--- /dev/null
+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"))
+ }
+
+}
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>()
@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
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)