From 0f0f4c89310e912c996b766ebe170ecb0f20ddf0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Fri, 7 Apr 2017 22:55:21 +0200 Subject: [PATCH] Add page that renders linked elements --- .../net/pterodactylus/sone/web/WebInterface.java | 5 +- .../kotlin/net/pterodactylus/sone/utils/Json.kt | 2 + .../sone/web/ajax/GetLinkedElementAjaxPage.kt | 48 +++++++++++++++++ .../sone/web/ajax/GetLinkedElementAjaxPageTest.kt | 60 ++++++++++++++++++++++ 4 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPage.kt create mode 100644 src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPageTest.kt diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index 8f7203c..6ce38d4 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -120,6 +120,7 @@ import net.pterodactylus.sone.web.ajax.EditImageAjaxPage; import net.pterodactylus.sone.web.ajax.EditProfileFieldAjaxPage; import net.pterodactylus.sone.web.ajax.FollowSoneAjaxPage; import net.pterodactylus.sone.web.ajax.GetLikesAjaxPage; +import net.pterodactylus.sone.web.ajax.GetLinkedElementAjaxPage; import net.pterodactylus.sone.web.ajax.GetNotificationsAjaxPage; import net.pterodactylus.sone.web.ajax.GetPostAjaxPage; import net.pterodactylus.sone.web.ajax.GetReplyAjaxPage; @@ -215,6 +216,7 @@ public class WebInterface { private final ReplyVisibilityFilter replyVisibilityFilter; private final ElementLoader elementLoader; + private final LinkedElementRenderFilter linkedElementRenderFilter; private final TimeTextConverter timeTextConverter = new TimeTextConverter(); private final L10nFilter l10nFilter = new L10nFilter(this); @@ -304,7 +306,7 @@ public class WebInterface { templateContextFactory.addFilter("shorten", shortenFilter = new ShortenFilter()); templateContextFactory.addFilter("render", renderFilter = new RenderFilter(getCore(), templateContextFactory)); templateContextFactory.addFilter("linked-elements", new LinkedElementsFilter(elementLoader)); - templateContextFactory.addFilter("render-linked-element", new LinkedElementRenderFilter(templateContextFactory)); + templateContextFactory.addFilter("render-linked-element", linkedElementRenderFilter = new LinkedElementRenderFilter(templateContextFactory)); templateContextFactory.addFilter("reparse", new ReparseFilter()); templateContextFactory.addFilter("unknown", new UnknownDateFilter(getL10n(), "View.Sone.Text.UnknownDate")); templateContextFactory.addFilter("format", new FormatFilter()); @@ -720,6 +722,7 @@ public class WebInterface { pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateReplyAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new GetReplyAjaxPage(this, replyTemplate))); pageToadlets.add(pageToadletFactory.createPageToadlet(new GetPostAjaxPage(this, postTemplate))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new GetLinkedElementAjaxPage(this, elementLoader, linkedElementRenderFilter))); pageToadlets.add(pageToadletFactory.createPageToadlet(new GetTimesAjaxPage(this, timeTextConverter, l10nFilter))); pageToadlets.add(pageToadletFactory.createPageToadlet(new MarkAsKnownAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new DeletePostAjaxPage(this))); diff --git a/src/main/kotlin/net/pterodactylus/sone/utils/Json.kt b/src/main/kotlin/net/pterodactylus/sone/utils/Json.kt index fc78b96..008c141 100644 --- a/src/main/kotlin/net/pterodactylus/sone/utils/Json.kt +++ b/src/main/kotlin/net/pterodactylus/sone/utils/Json.kt @@ -1,10 +1,12 @@ package net.pterodactylus.sone.utils +import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.node.ArrayNode import com.fasterxml.jackson.databind.node.JsonNodeFactory.instance import com.fasterxml.jackson.databind.node.ObjectNode fun jsonObject(block: ObjectNode.() -> Unit): ObjectNode = ObjectNode(instance).apply(block) fun jsonArray(vararg objects: String?): ArrayNode = objects.fold(ArrayNode(instance), ArrayNode::add) +fun jsonArray(vararg objects: JsonNode?): ArrayNode = objects.fold(ArrayNode(instance), ArrayNode::add) fun Iterable.toArray(): ArrayNode = fold(ArrayNode(instance), ArrayNode::add) diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPage.kt new file mode 100644 index 0000000..285c479 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPage.kt @@ -0,0 +1,48 @@ +package net.pterodactylus.sone.web.ajax + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import net.pterodactylus.sone.core.ElementLoader +import net.pterodactylus.sone.core.LinkedElement +import net.pterodactylus.sone.template.LinkedElementRenderFilter +import net.pterodactylus.sone.utils.jsonArray +import net.pterodactylus.sone.utils.jsonObject +import net.pterodactylus.sone.web.WebInterface +import net.pterodactylus.sone.web.page.FreenetRequest + +/** + * Renders linked elements after they have been loaded. + */ +class GetLinkedElementAjaxPage(webInterface: WebInterface, private val elementLoader: ElementLoader, private val linkedElementRenderFilter: LinkedElementRenderFilter): + JsonPage("getLinkedElement.ajax", webInterface) { + + override fun createJsonObject(request: FreenetRequest): JsonReturnObject = + request.httpRequest.getParam("elements", "[]").asJson() + .map(JsonNode::asText) + .map(elementLoader::loadElement) + .filterNot { it.loading } + .map { it to renderLinkedElement(it) } + .let { elements -> + jsonArray( + *(elements.map { element -> + jsonObject { + put("link", element.first.link) + put("html", element.second) + } + }.toTypedArray()) + ) + }.let { linkedElements -> + createSuccessJsonObject().apply { + put("linkedElements", linkedElements) + } + } + + override fun needsFormPassword() = false + override fun requiresLogin() = false + + private fun String.asJson() = ObjectMapper().readTree(this).asIterable() + + private fun renderLinkedElement(linkedElement: LinkedElement) = + linkedElementRenderFilter.format(null, linkedElement, emptyMap()) + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPageTest.kt new file mode 100644 index 0000000..ea3be1a --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetLinkedElementAjaxPageTest.kt @@ -0,0 +1,60 @@ +package net.pterodactylus.sone.web.ajax + +import com.fasterxml.jackson.databind.JsonNode +import net.pterodactylus.sone.core.LinkedElement +import net.pterodactylus.sone.template.LinkedElementRenderFilter +import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.utils.jsonArray +import net.pterodactylus.util.template.TemplateContext +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers +import org.hamcrest.Matchers.equalTo +import org.junit.Test +import org.mockito.ArgumentMatchers + +/** + * Unit test for [GetLinkedElementAjaxPage]. + */ +class GetLinkedElementAjaxPageTest: JsonPageTest() { + + private val linkedElementRenderFilter = mock() + override var page: JsonPage = GetLinkedElementAjaxPage(webInterface, elementLoader, linkedElementRenderFilter) + + @Test + fun `page returns correct path`() { + assertThat(page.path, equalTo("getLinkedElement.ajax")) + } + + @Test + fun `page does not require login`() { + assertThat(page.requiresLogin(), equalTo(false)) + } + + @Test + fun `page does not require form password`() { + assertThat(page.needsFormPassword(), equalTo(false)) + } + + @Test + fun `only loaded linked elements are returned`() { + addRequestParameter("elements", jsonArray("KSK@foo.png", "KSK@foo.jpg", "KSK@foo.html").toString()) + addLinkedElement("KSK@foo.png", true, false) + addLinkedElement("KSK@foo.jpg", false, false) + addLinkedElement("KSK@foo.html", false, true) + whenever(linkedElementRenderFilter.format(ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any())).thenAnswer { invocation -> + when (invocation.getArgument(1).link) { + "KSK@foo.jpg" -> "jpeg-image" + "KSK@foo.html" -> "html-page" + else -> null + } + } + assertThat(json.get("linkedElements").elements().asSequence().map { it.toMap() }.toList(), Matchers.containsInAnyOrder( + mapOf("link" to "KSK@foo.jpg", "html" to "jpeg-image"), + mapOf("link" to "KSK@foo.html", "html" to "html-page") + )) + } + + private fun JsonNode.toMap() = fields().asSequence().map { it.key!! to if (it.value.isNull) null else it.value.asText()!! }.toMap() + +} -- 2.7.4