From dd96e781b592c3bae9b0f66f85ba05a4e4cc18ce Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sun, 2 Apr 2017 11:36:02 +0200 Subject: [PATCH 1/1] Let status page give out information about loaded elements --- .../java/net/pterodactylus/sone/web/WebInterface.java | 4 +++- src/main/kotlin/net/pterodactylus/sone/utils/Json.kt | 1 + .../net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt | 16 +++++++++++++++- src/test/kotlin/net/pterodactylus/sone/utils/JsonTest.kt | 6 ++++++ .../pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt | 16 +++++++++++++++- .../net/pterodactylus/sone/web/ajax/JsonPageTest.kt | 16 ++++++++++++++++ 6 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index 30613af..8f7203c 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -214,6 +214,7 @@ public class WebInterface { private final PostVisibilityFilter postVisibilityFilter; private final ReplyVisibilityFilter replyVisibilityFilter; + private final ElementLoader elementLoader; private final TimeTextConverter timeTextConverter = new TimeTextConverter(); private final L10nFilter l10nFilter = new L10nFilter(this); @@ -272,6 +273,7 @@ public class WebInterface { this.listNotificationFilter = listNotificationFilter; this.postVisibilityFilter = postVisibilityFilter; this.replyVisibilityFilter = replyVisibilityFilter; + this.elementLoader = elementLoader; formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword(); soneTextParser = new SoneTextParser(getCore(), getCore()); @@ -711,7 +713,7 @@ public class WebInterface { pageToadlets.add(pageToadletFactory.createPageToadlet(new TemplatePage("OpenSearch.xml", "application/opensearchdescription+xml", templateContextFactory, openSearchTemplate))); pageToadlets.add(pageToadletFactory.createPageToadlet(new GetImagePage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new GetTranslationPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new GetStatusAjaxPage(this, timeTextConverter, l10nFilter))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new GetStatusAjaxPage(this, elementLoader, timeTextConverter, l10nFilter))); pageToadlets.add(pageToadletFactory.createPageToadlet(new GetNotificationsAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new DismissNotificationAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new CreatePostAjaxPage(this))); diff --git a/src/main/kotlin/net/pterodactylus/sone/utils/Json.kt b/src/main/kotlin/net/pterodactylus/sone/utils/Json.kt index 7a09a4d..fc78b96 100644 --- a/src/main/kotlin/net/pterodactylus/sone/utils/Json.kt +++ b/src/main/kotlin/net/pterodactylus/sone/utils/Json.kt @@ -5,5 +5,6 @@ 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 Iterable.toArray(): ArrayNode = fold(ArrayNode(instance), ArrayNode::add) diff --git a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt index 21d296a..d7884bf 100644 --- a/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt +++ b/src/main/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.kt @@ -1,6 +1,9 @@ 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.data.Post import net.pterodactylus.sone.data.PostReply import net.pterodactylus.sone.data.Sone @@ -18,7 +21,7 @@ import java.text.SimpleDateFormat * The “get status” AJAX handler returns all information that is necessary to * update the web interface in real-time. */ -class GetStatusAjaxPage(webInterface: WebInterface, private val timeTextConverter: TimeTextConverter, private val l10nFilter: L10nFilter): +class GetStatusAjaxPage(webInterface: WebInterface, private val elementLoader: ElementLoader, private val timeTextConverter: TimeTextConverter, private val l10nFilter: L10nFilter): JsonPage("getStatus.ajax", webInterface) { private val dateFormatter = SimpleDateFormat("MMM d, yyyy, HH:mm:ss") @@ -32,6 +35,7 @@ class GetStatusAjaxPage(webInterface: WebInterface, private val timeTextConverte this["sones"] = request.httpRequest.getParam("soneIds").split(',').map { webInterface.core.getSone(it).orNull() }.plus(currentSone).filterNotNull().toJsonSones() this["newPosts"] = webInterface.getNewPosts(currentSone).toJsonPosts() this["newReplies"] = webInterface.getNewReplies(currentSone).toJsonReplies() + this["loadedElements"] = request.httpRequest.getParam("elements", "[]").asJson().map(JsonNode::asText).map(elementLoader::loadElement).toJsonElements() } } @@ -39,6 +43,8 @@ class GetStatusAjaxPage(webInterface: WebInterface, private val timeTextConverte private operator fun JsonReturnObject.set(key: String, value: Int) = put(key, value) private operator fun JsonReturnObject.set(key: String, value: Boolean) = put(key, value) + private fun String.asJson() = ObjectMapper().readTree(this).asIterable() + override fun needsFormPassword() = false override fun requiresLogin() = false @@ -82,4 +88,12 @@ class GetStatusAjaxPage(webInterface: WebInterface, private val timeTextConverte } }.toArray() + private fun Iterable.toJsonElements() = map { (link, failed, loading) -> + jsonObject { + put("link", link) + put("loading", loading) + put("failed", failed) + } + }.toArray() + } diff --git a/src/test/kotlin/net/pterodactylus/sone/utils/JsonTest.kt b/src/test/kotlin/net/pterodactylus/sone/utils/JsonTest.kt index ff741c1..abf391d 100644 --- a/src/test/kotlin/net/pterodactylus/sone/utils/JsonTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/utils/JsonTest.kt @@ -31,4 +31,10 @@ class JsonTest { assertThat(arrayNode.toString(), equalTo("[{\"foo\":\"bar\"},{\"baz\":\"quo\"}]")) } + @Test + fun `array is created correctly for strings`() { + val arrayNode = jsonArray("foo", "bar", "baz") + assertThat(arrayNode.toString(), equalTo("[\"foo\",\"bar\",\"baz\"]")) + } + } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt index d397b93..9ec927d 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt @@ -11,6 +11,7 @@ import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever import net.pterodactylus.sone.text.TimeText import net.pterodactylus.sone.text.TimeTextConverter +import net.pterodactylus.sone.utils.jsonArray import net.pterodactylus.util.notify.Notification import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.allOf @@ -30,7 +31,7 @@ class GetStatusAjaxPageTest: JsonPageTest() { private val timeTextConverter = mock() private val l10nFilter = mock() - override var page: JsonPage = GetStatusAjaxPage(webInterface, timeTextConverter, l10nFilter) + override var page: JsonPage = GetStatusAjaxPage(webInterface, elementLoader, timeTextConverter, l10nFilter) @Before fun setupTimeTextConverter() { @@ -134,6 +135,19 @@ class GetStatusAjaxPageTest: JsonPageTest() { )) } + @Test + fun `page returns information about loaded elements`() { + addLoadedElement("KSK@test.png", loading = false, failed = false) + addLoadedElement("KSK@test.html", loading = true, failed = false) + addLoadedElement("KSK@test.jpeg", loading = false, failed = true) + addRequestParameter("elements", jsonArray("KSK@test.png", "KSK@test.html", "KSK@test.jpeg").toString()) + assertThat(json.get("loadedElements").elements().asSequence().map { it.toMap() }.toList(), containsInAnyOrder( + mapOf("link" to "KSK@test.png", "loading" to "false", "failed" to "false"), + mapOf("link" to "KSK@test.html", "loading" to "true", "failed" to "false"), + mapOf("link" to "KSK@test.jpeg", "loading" to "false", "failed" to "true") + )) + } + private fun JsonNode.toMap() = fields().asSequence().map { it.key!! to if (it.value.isNull) null else it.value.asText()!! }.toMap() } diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt index 84f74f9..9b19aa3 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt @@ -3,6 +3,8 @@ package net.pterodactylus.sone.web.ajax import freenet.clients.http.ToadletContext import freenet.support.api.HTTPRequest import net.pterodactylus.sone.core.Core +import net.pterodactylus.sone.core.ElementLoader +import net.pterodactylus.sone.core.LinkedElement import net.pterodactylus.sone.data.Post import net.pterodactylus.sone.data.PostReply import net.pterodactylus.sone.data.Sone @@ -25,6 +27,7 @@ open class JsonPageTest { protected val webInterface = mock() protected val core = mock() + protected val elementLoader = mock() protected open lateinit var page: JsonPage protected val json by lazy { page.createJsonObject(freenetRequest)!! } @@ -38,6 +41,7 @@ open class JsonPageTest { private val remoteSones = mutableMapOf() private val newPosts = mutableMapOf() private val newReplies = mutableMapOf() + private val loadedElements = mutableMapOf() private val notifications = mutableListOf() @Before @@ -56,6 +60,13 @@ open class JsonPageTest { } @Before + fun setupElementLoader() { + whenever(elementLoader.loadElement(anyString())).thenAnswer { + loadedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true) + } + } + + @Before fun setupCurrentSone() { currentSone.mock("soneId", "Sone_Id", true, 1000, idle) } @@ -69,6 +80,7 @@ open class JsonPageTest { @Before fun setupHttpRequest() { whenever(httpRequest.getParam(anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: "" } + whenever(httpRequest.getParam(anyString(), anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: it.getArgument(1) } } protected fun Sone.mock(id: String, name: String, local: Boolean = false, time: Long, status: SoneStatus = idle) = apply { @@ -120,4 +132,8 @@ open class JsonPageTest { } } + protected fun addLoadedElement(link: String, loading: Boolean, failed: Boolean) { + loadedElements[link] = LinkedElement(link, failed, loading) + } + } -- 2.7.4