package net.pterodactylus.sone.web;
import static java.util.logging.Logger.getLogger;
-import static java.util.stream.Collectors.toSet;
import java.util.Collection;
-import java.util.Set;
import java.util.TimeZone;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import javax.inject.Named;
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.core.ElementLoader;
import net.pterodactylus.sone.main.PluginVersion;
import net.pterodactylus.sone.main.PluginYear;
import net.pterodactylus.sone.main.SonePlugin;
-import net.pterodactylus.sone.notify.ListNotification;
import net.pterodactylus.sone.notify.ListNotificationFilter;
import net.pterodactylus.sone.notify.PostVisibilityFilter;
-import net.pterodactylus.sone.notify.ReplyVisibilityFilter;
import net.pterodactylus.sone.template.LinkedElementRenderFilter;
import net.pterodactylus.sone.template.ParserFilter;
import net.pterodactylus.sone.template.RenderFilter;
import com.codahale.metrics.*;
import com.google.common.base.Optional;
-import com.google.common.collect.ImmutableSet;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
import freenet.clients.http.ToadletContext;
*/
public class WebInterface implements SessionProvider {
- /** The logger. */
- private static final Logger logger = getLogger(WebInterface.class.getName());
-
/** The loaders for templates, pages, and classpath providers. */
private final Loaders loaders;
private final ListNotificationFilter listNotificationFilter;
private final PostVisibilityFilter postVisibilityFilter;
- private final ReplyVisibilityFilter replyVisibilityFilter;
private final ElementLoader elementLoader;
private final LinkedElementRenderFilter linkedElementRenderFilter;
private final Translation translation;
private final SessionProvider sessionProvider;
- /** The “new post” notification. */
- private final ListNotification<Post> newPostNotification;
-
- /** The “new reply” notification. */
- private final ListNotification<PostReply> newReplyNotification;
-
- /** The invisible “local post” notification. */
- private final ListNotification<Post> localPostNotification;
-
- /** The invisible “local reply” notification. */
- private final ListNotification<PostReply> localReplyNotification;
+ private final NewElements newElements;
@Inject
public WebInterface(SonePlugin sonePlugin, Loaders loaders, ListNotificationFilter listNotificationFilter,
- PostVisibilityFilter postVisibilityFilter, ReplyVisibilityFilter replyVisibilityFilter,
- ElementLoader elementLoader, TemplateContextFactory templateContextFactory,
- TemplateRenderer templateRenderer,
- ParserFilter parserFilter, ShortenFilter shortenFilter,
- RenderFilter renderFilter,
- LinkedElementRenderFilter linkedElementRenderFilter,
- PageToadletRegistry pageToadletRegistry, MetricRegistry metricRegistry, Translation translation, L10nFilter l10nFilter,
- NotificationManager notificationManager, SessionProvider sessionProvider,
- @Named("newRemotePost") ListNotification<Post> newPostNotification,
- @Named("newRemotePostReply") ListNotification<PostReply> newReplyNotification,
- @Named("localPost") ListNotification<Post> localPostNotification,
- @Named("localReply") ListNotification<PostReply> localReplyNotification) {
+ PostVisibilityFilter postVisibilityFilter,
+ ElementLoader elementLoader, TemplateContextFactory templateContextFactory,
+ TemplateRenderer templateRenderer,
+ ParserFilter parserFilter, ShortenFilter shortenFilter,
+ RenderFilter renderFilter,
+ LinkedElementRenderFilter linkedElementRenderFilter,
+ PageToadletRegistry pageToadletRegistry, MetricRegistry metricRegistry, Translation translation, L10nFilter l10nFilter,
+ NotificationManager notificationManager, SessionProvider sessionProvider,
+ NewElements newElements) {
this.sonePlugin = sonePlugin;
this.loaders = loaders;
this.listNotificationFilter = listNotificationFilter;
this.postVisibilityFilter = postVisibilityFilter;
- this.replyVisibilityFilter = replyVisibilityFilter;
this.elementLoader = elementLoader;
this.templateRenderer = templateRenderer;
this.parserFilter = parserFilter;
this.translation = translation;
this.notificationManager = notificationManager;
this.sessionProvider = sessionProvider;
- this.newPostNotification = newPostNotification;
- this.newReplyNotification = newReplyNotification;
- this.localPostNotification = localPostNotification;
- this.localReplyNotification = localReplyNotification;
+ this.newElements = newElements;
formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword();
this.templateContextFactory = templateContextFactory;
@Nonnull
public Collection<Post> getNewPosts(@Nullable Sone currentSone) {
- Set<Post> allNewPosts = ImmutableSet.<Post> builder()
- .addAll(newPostNotification.getElements())
- .addAll(localPostNotification.getElements())
- .build();
- return allNewPosts.stream().filter(p -> postVisibilityFilter.isPostVisible(currentSone, p)).collect(toSet());
+ return newElements.getNewPosts();
}
@Nonnull
public Collection<PostReply> getNewReplies(@Nullable Sone currentSone) {
- Set<PostReply> allNewReplies = ImmutableSet.<PostReply>builder()
- .addAll(newReplyNotification.getElements())
- .addAll(localReplyNotification.getElements())
- .build();
- return allNewReplies.stream().filter(r -> replyVisibilityFilter.isReplyVisible(currentSone, r)).collect(toSet());
+ return newElements.getNewReplies();
}
//
--- /dev/null
+/**
+ * Sone - NewElements.kt - Copyright © 2020 David ‘Bombe’ 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
+
+import net.pterodactylus.sone.data.Post
+import net.pterodactylus.sone.data.PostReply
+import net.pterodactylus.sone.notify.ListNotification
+import net.pterodactylus.sone.notify.PostVisibilityFilter
+import net.pterodactylus.sone.notify.ReplyVisibilityFilter
+import javax.inject.Inject
+import javax.inject.Named
+
+/**
+ * Container for new elements that should be shown in the web interface.
+ *
+ * This is just a wrapper around the notifications that store the new elements.
+ */
+class NewElements @Inject constructor(
+ @Named("newRemotePost") private val newPostNotification: ListNotification<Post>,
+ @Named("newRemotePostReply") private val newReplyNotification: ListNotification<PostReply>,
+ @Named("localPost") private val localPostNotification: ListNotification<Post>,
+ @Named("localReply") private val localReplyNotification: ListNotification<PostReply>,
+ private val postVisibilityFilter: PostVisibilityFilter,
+ private val replyVisibilityFilter: ReplyVisibilityFilter
+) {
+
+ val newPosts: Collection<Post>
+ get() = listOf(newPostNotification, localPostNotification)
+ .flatMap(ListNotification<Post>::elements)
+ .filter { postVisibilityFilter.isPostVisible(null, it) }
+
+ val newReplies: Collection<PostReply>
+ get() = listOf(newReplyNotification, localReplyNotification)
+ .flatMap(ListNotification<PostReply>::elements)
+ .filter { replyVisibilityFilter.isReplyVisible(null, it) }
+}
+
+private fun <R> Collection<*>.cast(): List<R> = map { it as R }
package net.pterodactylus.sone.test
-import com.google.inject.*
-import com.google.inject.name.*
-import org.hamcrest.MatcherAssert.*
-import org.hamcrest.Matchers.*
-import org.mockito.*
+import com.google.inject.Injector
+import com.google.inject.Key
+import com.google.inject.Module
+import com.google.inject.TypeLiteral
+import com.google.inject.name.Names
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.sameInstance
+import org.mockito.Mockito
import javax.inject.Provider
-import kotlin.reflect.*
+import kotlin.reflect.KClass
fun <T : Any> KClass<T>.isProvidedBy(instance: T) = Module { it.bind(this.java).toProvider(Provider<T> { instance }) }
fun <T : Any> KClass<T>.withNameIsProvidedBy(instance: T, name: String) = Module { it.bind(this.java).annotatedWith(Names.named(name)).toProvider(Provider<T> { instance }) }
fun <T : Any> KClass<T>.isProvidedBy(provider: com.google.inject.Provider<T>) = Module { it.bind(this.java).toProvider(provider) }
fun <T : Any> KClass<T>.isProvidedBy(provider: KClass<out Provider<T>>) = Module { it.bind(this.java).toProvider(provider.java) }
+fun <T : Any> Key<T>.isProvidedBy(instance: T) = Module { it.bind(this).toProvider(Provider<T> { instance }) }
inline fun <reified T : Any> KClass<T>.isProvidedByMock() = Module { it.bind(this.java).toProvider(Provider<T> { mock() }) }
inline fun <reified T : Any> KClass<T>.isProvidedByDeepMock() = Module { it.bind(this.java).toProvider(Provider<T> { deepMock() }) }
+inline fun <reified T> key(): Key<T> = Key.get(object : TypeLiteral<T>() {})
+inline fun <reified T> key(annotation: Annotation): Key<T> = Key.get(object : TypeLiteral<T>() {}, annotation)
+
inline fun <reified T : Any> Injector.getInstance(annotation: Annotation? = null): T = annotation
?.let { getInstance(Key.get(object : TypeLiteral<T>() {}, it)) }
?: getInstance(Key.get(object : TypeLiteral<T>() {}))
--- /dev/null
+/**
+ * Sone - NewElementsTest.kt - Copyright © 2020 David ‘Bombe’ 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
+
+import com.google.inject.Guice
+import com.google.inject.name.Names.named
+import net.pterodactylus.sone.data.Post
+import net.pterodactylus.sone.data.PostReply
+import net.pterodactylus.sone.notify.ListNotification
+import net.pterodactylus.sone.notify.matchThisPost
+import net.pterodactylus.sone.notify.matchThisReply
+import net.pterodactylus.sone.notify.showAllPosts
+import net.pterodactylus.sone.notify.showAllReplies
+import net.pterodactylus.sone.test.createPost
+import net.pterodactylus.sone.test.createPostReply
+import net.pterodactylus.sone.test.getInstance
+import net.pterodactylus.sone.test.isProvidedBy
+import net.pterodactylus.sone.test.key
+import net.pterodactylus.util.template.Template
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.contains
+import org.hamcrest.Matchers.containsInAnyOrder
+import org.junit.Test
+
+class NewElementsTest {
+
+ private val newPostNotification = ListNotification<Post>("", "", Template())
+ private val newReplyNotification = ListNotification<PostReply>("", "", Template())
+ private val localPostNotification = ListNotification<Post>("", "", Template())
+ private val localReplyNotification = ListNotification<PostReply>("", "", Template())
+ private val newElements = NewElements(newPostNotification, newReplyNotification, localPostNotification, localReplyNotification, showAllPosts, showAllReplies)
+
+ init {
+ localPostNotification.add(post1)
+ newPostNotification.add(post2)
+ localReplyNotification.add(reply1)
+ newReplyNotification.add(reply2)
+ }
+
+ @Test
+ fun `new elements container can be created by guice`() {
+ val injector = Guice.createInjector(
+ key<ListNotification<Post>>(named("newRemotePost")).isProvidedBy(newPostNotification),
+ key<ListNotification<Post>>(named("localPost")).isProvidedBy(localPostNotification),
+ key<ListNotification<PostReply>>(named("newRemotePostReply")).isProvidedBy(newReplyNotification),
+ key<ListNotification<PostReply>>(named("localReply")).isProvidedBy(localReplyNotification)
+ )
+ injector.getInstance<NewElements>()
+ }
+
+ @Test
+ fun `new posts include new and local posts`() {
+ assertThat(newElements.newPosts, containsInAnyOrder(post1, post2))
+ }
+
+ @Test
+ fun `new posts are filtered`() {
+ val newElements = NewElements(newPostNotification, newReplyNotification, localPostNotification, localReplyNotification, matchThisPost(post2), showAllReplies)
+ assertThat(newElements.newPosts, contains(post2))
+ }
+
+ @Test
+ fun `new replies include new and local replies`() {
+ assertThat(newElements.newReplies, containsInAnyOrder(reply1, reply2))
+ }
+
+ @Test
+ fun `new replies are filtered`() {
+ val newElements = NewElements(newPostNotification, newReplyNotification, localPostNotification, localReplyNotification, showAllPosts, matchThisReply(reply2))
+ assertThat(newElements.newReplies, containsInAnyOrder(reply2))
+ }
+
+}
+
+private val post1 = createPost()
+private val post2 = createPost()
+private val reply1 = createPostReply()
+private val reply2 = createPostReply()