From cc13ef909d3b9e265918e396466c320ce63235ae Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Wed, 3 May 2017 21:32:36 +0200 Subject: [PATCH] Replace index page with Kotlin version --- .../pterodactylus/sone/web/pages/IndexPage.java | 88 ---------------------- .../net/pterodactylus/sone/web/pages/IndexPage.kt | 40 ++++++++++ .../pterodactylus/sone/web/pages/IndexPageTest.kt | 62 +++++++++++++-- 3 files changed, 97 insertions(+), 93 deletions(-) delete mode 100644 src/main/java/net/pterodactylus/sone/web/pages/IndexPage.java create mode 100644 src/main/kotlin/net/pterodactylus/sone/web/pages/IndexPage.kt diff --git a/src/main/java/net/pterodactylus/sone/web/pages/IndexPage.java b/src/main/java/net/pterodactylus/sone/web/pages/IndexPage.java deleted file mode 100644 index 5946a57..0000000 --- a/src/main/java/net/pterodactylus/sone/web/pages/IndexPage.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Sone - IndexPage.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 . - */ - -package net.pterodactylus.sone.web.pages; - -import static net.pterodactylus.sone.utils.NumberParsers.parseInt; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Sone; -import net.pterodactylus.sone.notify.PostVisibilityFilter; -import net.pterodactylus.sone.web.WebInterface; -import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.collection.Pagination; -import net.pterodactylus.util.template.Template; -import net.pterodactylus.util.template.TemplateContext; - -import com.google.common.base.Optional; -import com.google.common.collect.Collections2; - -/** - * The index page shows the main page of Sone. This page will contain the posts - * of all friends of the current user. - * - * @author David ‘Bombe’ Roden - */ -public class IndexPage extends SoneTemplatePage { - - private final PostVisibilityFilter postVisibilityFilter; - - public IndexPage(Template template, WebInterface webInterface, PostVisibilityFilter postVisibilityFilter) { - super("index.html", template, "Page.Index.Title", webInterface, true); - this.postVisibilityFilter = postVisibilityFilter; - } - - // - // TEMPLATEPAGE METHODS - // - - /** - * {@inheritDoc} - */ - @Override - protected void handleRequest(FreenetRequest request, TemplateContext templateContext) throws RedirectException { - final Sone currentSone = getCurrentSone(request.getToadletContext()); - Collection allPosts = new ArrayList(); - allPosts.addAll(currentSone.getPosts()); - for (String friendSoneId : currentSone.getFriends()) { - Optional friendSone = webInterface.getCore().getSone(friendSoneId); - if (!friendSone.isPresent()) { - continue; - } - allPosts.addAll(friendSone.get().getPosts()); - } - for (Sone sone : webInterface.getCore().getSones()) { - for (Post post : sone.getPosts()) { - if (currentSone.equals(post.getRecipient().orNull()) && !allPosts.contains(post)) { - allPosts.add(post); - } - } - } - allPosts = Collections2.filter(allPosts, postVisibilityFilter.isVisible(currentSone)); - List sortedPosts = new ArrayList(allPosts); - Collections.sort(sortedPosts, Post.NEWEST_FIRST); - Pagination pagination = new Pagination(sortedPosts, webInterface.getCore().getPreferences().getPostsPerPage()).setPage(parseInt(request.getHttpRequest().getParam("page"), 0)); - templateContext.set("pagination", pagination); - templateContext.set("posts", pagination.getItems()); - } - -} diff --git a/src/main/kotlin/net/pterodactylus/sone/web/pages/IndexPage.kt b/src/main/kotlin/net/pterodactylus/sone/web/pages/IndexPage.kt new file mode 100644 index 0000000..7753b40 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/pages/IndexPage.kt @@ -0,0 +1,40 @@ +package net.pterodactylus.sone.web.pages + +import net.pterodactylus.sone.notify.PostVisibilityFilter +import net.pterodactylus.sone.utils.parameters +import net.pterodactylus.sone.web.WebInterface +import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.util.collection.Pagination +import net.pterodactylus.util.template.Template +import net.pterodactylus.util.template.TemplateContext + +/** + * The index page shows the main page of Sone. This page will contain the posts + * of all friends of the current user. + */ +class IndexPage(template: Template, webInterface: WebInterface, private val postVisibilityFilter: PostVisibilityFilter): + SoneTemplatePage("index.html", template, "Page.Index.Title", webInterface, true) { + + override fun handleRequest(request: FreenetRequest, templateContext: TemplateContext) { + getCurrentSone(request.toadletContext)!!.let { currentSone -> + (currentSone.posts + + currentSone.friends + .map { webInterface.core.getSone(it) } + .filter { it.isPresent } + .map { it.get() } + .flatMap { it.posts } + + webInterface.core.getDirectedPosts(currentSone.id) + ).distinct() + .filter { postVisibilityFilter.isVisible(currentSone).apply(it) } + .sortedByDescending { it.time } + .let { posts -> + Pagination(posts, webInterface.core.preferences.postsPerPage) + .setPage(request.parameters["page"]?.toIntOrNull() ?: 0).let { pagination -> + templateContext["pagination"] = pagination + templateContext["posts"] = pagination.items + } + } + } + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/pages/IndexPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/pages/IndexPageTest.kt index 978e8ed..243e597 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/pages/IndexPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/pages/IndexPageTest.kt @@ -7,8 +7,7 @@ import net.pterodactylus.sone.data.Sone import net.pterodactylus.sone.notify.PostVisibilityFilter import net.pterodactylus.sone.test.mock import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.web.pages.IndexPage -import net.pterodactylus.sone.web.pages.WebPageTest +import net.pterodactylus.util.collection.Pagination import net.pterodactylus.util.web.Method.GET import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.contains @@ -46,6 +45,16 @@ class IndexPageTest : WebPageTest() { whenever(postVisibilityFilter.isVisible(ArgumentMatchers.eq(currentSone))).thenReturn(Predicate { true }) } + @Before + fun setupCurrentSone() { + whenever(currentSone.id).thenReturn("current") + } + + @Before + fun setupDirectedPosts() { + whenever(core.getDirectedPosts("current")).thenReturn(emptyList()) + } + private fun createPost(time: Long, directed: Boolean = false) = mock().apply { whenever(this.time).thenReturn(time) whenever(recipient).thenReturn(fromNullable(if (directed) currentSone else null)) @@ -56,7 +65,7 @@ class IndexPageTest : WebPageTest() { val posts = listOf(createPost(3000), createPost(2000), createPost(1000)) whenever(currentSone.posts).thenReturn(posts) request("", GET) - page.handleRequest(freenetRequest, templateContext) + page.processTemplate(freenetRequest, templateContext) @Suppress("UNCHECKED_CAST") assertThat(templateContext["posts"] as Iterable, contains(*posts.toTypedArray())) } @@ -70,7 +79,8 @@ class IndexPageTest : WebPageTest() { whenever(notFollowedSone.posts).thenReturn(notFollowedPosts) addSone("notfollowed1", notFollowedSone) request("", GET) - page.handleRequest(freenetRequest, templateContext) + whenever(core.getDirectedPosts("current")).thenReturn(listOf(notFollowedPosts[0])) + page.processTemplate(freenetRequest, templateContext) @Suppress("UNCHECKED_CAST") assertThat(templateContext["posts"] as Iterable, contains( posts[0], notFollowedPosts[0], posts[1], posts[2] @@ -87,11 +97,53 @@ class IndexPageTest : WebPageTest() { whenever(currentSone.friends).thenReturn(listOf("followed1", "followed2")) addSone("followed1", followedSone) request("", GET) - page.handleRequest(freenetRequest, templateContext) + page.processTemplate(freenetRequest, templateContext) @Suppress("UNCHECKED_CAST") assertThat(templateContext["posts"] as Iterable, contains( posts[0], followedPosts[0], posts[1], followedPosts[1], posts[2] )) } + @Test + fun `index page uses post visibility filter`() { + val posts = listOf(createPost(3000), createPost(2000), createPost(1000)) + whenever(currentSone.posts).thenReturn(posts) + val followedSone = mock() + val followedPosts = listOf(createPost(2500, true), createPost(1500)) + whenever(followedSone.posts).thenReturn(followedPosts) + whenever(currentSone.friends).thenReturn(listOf("followed1", "followed2")) + whenever(postVisibilityFilter.isVisible(ArgumentMatchers.eq(currentSone))).thenReturn(Predicate { (it?.time ?: 10000) < 2500 }) + addSone("followed1", followedSone) + request("", GET) + page.processTemplate(freenetRequest, templateContext) + @Suppress("UNCHECKED_CAST") + assertThat(templateContext["posts"] as Iterable, contains( + posts[1], followedPosts[1], posts[2] + )) + } + + @Test + fun `index page sets pagination correctly`() { + val posts = listOf(createPost(3000), createPost(2000), createPost(1000)) + whenever(currentSone.posts).thenReturn(posts) + request("", GET) + page.processTemplate(freenetRequest, templateContext) + @Suppress("UNCHECKED_CAST") + assertThat((templateContext["pagination"] as Pagination).items, contains( + posts[0], posts[1], posts[2] + )) + } + + @Test + fun `index page sets page correctly`() { + val posts = listOf(createPost(3000), createPost(2000), createPost(1000)) + whenever(currentSone.posts).thenReturn(posts) + request("", GET) + core.preferences.postsPerPage = 1 + addHttpRequestParameter("page", "2") + page.processTemplate(freenetRequest, templateContext) + @Suppress("UNCHECKED_CAST") + assertThat((templateContext["pagination"] as Pagination).page, equalTo(2)) + } + } -- 2.7.4