--- /dev/null
+package net.pterodactylus.sone.notify;
+
+import java.util.function.Predicate;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.inject.Singleton;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+import net.pterodactylus.sone.freenet.wot.Trust;
+import net.pterodactylus.util.notify.Notification;
+
+/**
+ * Filters {@link Notification}s involving {@link Post}s.
+ */
+@Singleton
+public class DefaultPostVisibilityFilter implements PostVisibilityFilter {
+
+ /**
+ * Checks whether a post is visible to the given Sone. A post is not
+ * considered visible if one of the following statements is true:
+ * <ul>
+ * <li>The post does not have a Sone.</li>
+ * <li>The post’s {@link Post#getTime() time} is in the future.</li>
+ * </ul>
+ * <p>
+ * If {@code post} is not {@code null} more checks are performed, and the
+ * post will be invisible if:
+ * </p>
+ * <ul>
+ * <li>The Sone of the post is not the given Sone, the given Sone does not
+ * follow the post’s Sone, and the given Sone is not the recipient of the
+ * post.</li>
+ * <li>The trust relationship between the two Sones can not be retrieved.</li>
+ * <li>The given Sone has explicitely assigned negative trust to the post’s
+ * Sone.</li>
+ * <li>The given Sone has not explicitely assigned negative trust to the
+ * post’s Sone but the implicit trust is negative.</li>
+ * </ul>
+ * If none of these statements is true the post is considered visible.
+ *
+ * @param sone
+ * The Sone that checks for a post’s visibility (may be
+ * {@code null} to skip Sone-specific checks, such as trust)
+ * @param post
+ * The post to check for visibility
+ * @return {@code true} if the post is considered visible, {@code false}
+ * otherwise
+ */
+ @Override
+ public boolean isPostVisible(@Nullable Sone sone, @Nonnull Post post) {
+ checkNotNull(post, "post must not be null");
+ if (!post.isLoaded()) {
+ return false;
+ }
+ Sone postSone = post.getSone();
+ if (sone != null) {
+ Trust trust = postSone.getIdentity().getTrust((OwnIdentity) sone.getIdentity());
+ if (trust != null) {
+ if ((trust.getExplicit() != null) && (trust.getExplicit() < 0)) {
+ return false;
+ }
+ if ((trust.getExplicit() == null) && (trust.getImplicit() != null) && (trust.getImplicit() < 0)) {
+ return false;
+ }
+ } else {
+ /*
+ * a null trust means that the trust updater has not yet
+ * received a trust value for this relation. if we return false,
+ * the post feed will stay empty until the trust updater has
+ * received trust values. to prevent this we simply assume that
+ * posts are visible if there is no trust.
+ */
+ }
+ if ((!postSone.equals(sone)) && !sone.hasFriend(postSone.getId()) && !sone.getId().equals(post.getRecipientId().orNull())) {
+ return false;
+ }
+ }
+ return post.getTime() <= System.currentTimeMillis();
+ }
+
+ @Override
+ @Nonnull
+ public Predicate<Post> isVisible(@Nullable final Sone currentSone) {
+ return post -> (post != null) && isPostVisible(currentSone, post);
+ }
+
+}
package net.pterodactylus.sone.notify;
import java.util.function.Predicate;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
-import javax.inject.Singleton;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.freenet.wot.OwnIdentity;
-import net.pterodactylus.sone.freenet.wot.Trust;
-import net.pterodactylus.util.notify.Notification;
-/**
- * Filters {@link Notification}s involving {@link Post}s.
- */
-@Singleton
-public class PostVisibilityFilter {
+import com.google.inject.ImplementedBy;
+
+@ImplementedBy(DefaultPostVisibilityFilter.class)
+public interface PostVisibilityFilter {
- /**
- * Checks whether a post is visible to the given Sone. A post is not
- * considered visible if one of the following statements is true:
- * <ul>
- * <li>The post does not have a Sone.</li>
- * <li>The post’s {@link Post#getTime() time} is in the future.</li>
- * </ul>
- * <p>
- * If {@code post} is not {@code null} more checks are performed, and the
- * post will be invisible if:
- * </p>
- * <ul>
- * <li>The Sone of the post is not the given Sone, the given Sone does not
- * follow the post’s Sone, and the given Sone is not the recipient of the
- * post.</li>
- * <li>The trust relationship between the two Sones can not be retrieved.</li>
- * <li>The given Sone has explicitely assigned negative trust to the post’s
- * Sone.</li>
- * <li>The given Sone has not explicitely assigned negative trust to the
- * post’s Sone but the implicit trust is negative.</li>
- * </ul>
- * If none of these statements is true the post is considered visible.
- *
- * @param sone
- * The Sone that checks for a post’s visibility (may be
- * {@code null} to skip Sone-specific checks, such as trust)
- * @param post
- * The post to check for visibility
- * @return {@code true} if the post is considered visible, {@code false}
- * otherwise
- */
- boolean isPostVisible(@Nullable Sone sone, @Nonnull Post post) {
- checkNotNull(post, "post must not be null");
- if (!post.isLoaded()) {
- return false;
- }
- Sone postSone = post.getSone();
- if (sone != null) {
- Trust trust = postSone.getIdentity().getTrust((OwnIdentity) sone.getIdentity());
- if (trust != null) {
- if ((trust.getExplicit() != null) && (trust.getExplicit() < 0)) {
- return false;
- }
- if ((trust.getExplicit() == null) && (trust.getImplicit() != null) && (trust.getImplicit() < 0)) {
- return false;
- }
- } else {
- /*
- * a null trust means that the trust updater has not yet
- * received a trust value for this relation. if we return false,
- * the post feed will stay empty until the trust updater has
- * received trust values. to prevent this we simply assume that
- * posts are visible if there is no trust.
- */
- }
- if ((!postSone.equals(sone)) && !sone.hasFriend(postSone.getId()) && !sone.getId().equals(post.getRecipientId().orNull())) {
- return false;
- }
- }
- return post.getTime() <= System.currentTimeMillis();
- }
+ boolean isPostVisible(@Nullable Sone sone, @Nonnull Post post);
@Nonnull
- public Predicate<Post> isVisible(@Nullable final Sone currentSone) {
- return post -> (post != null) && isPostVisible(currentSone, post);
- }
+ Predicate<Post> isVisible(@Nullable Sone currentSone);
}
--- /dev/null
+package net.pterodactylus.sone.notify
+
+import com.google.inject.Guice
+import net.pterodactylus.sone.freenet.wot.OwnIdentity
+import net.pterodactylus.sone.freenet.wot.Trust
+import net.pterodactylus.sone.test.createLocalSone
+import net.pterodactylus.sone.test.createPost
+import net.pterodactylus.sone.test.createRemoteSone
+import net.pterodactylus.sone.test.verifySingletonInstance
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.equalTo
+import org.junit.Test
+
+/**
+ * Unit test for [DefaultPostVisibilityFilter].
+ */
+class DefaultPostVisibilityFilterTest {
+
+ private val postVisibilityFilter = DefaultPostVisibilityFilter()
+ private val localSone = createLocalSone()
+ private val remoteSone = createRemoteSone()
+
+ @Test
+ fun `post visibility filter is only created once`() {
+ val injector = Guice.createInjector()
+ injector.verifySingletonInstance<PostVisibilityFilter>()
+ }
+
+ @Test
+ fun `post is not visible if it is not loaded`() {
+ val post = createPost(loaded = false)
+ assertThat(postVisibilityFilter.isPostVisible(null, post), equalTo(false))
+ }
+
+ @Test
+ fun `loaded post is visible without sone and in the past`() {
+ val post = createPost(sone = null)
+ assertThat(postVisibilityFilter.isPostVisible(null, post), equalTo(true))
+ }
+
+ @Test
+ fun `loaded post from the future is not visible`() {
+ // the offset for the future must be large enough to survive loading freenet.crypt.Util.
+ val post = createPost(time = System.currentTimeMillis() + 100000, sone = null)
+ assertThat(postVisibilityFilter.isPostVisible(null, post), equalTo(false))
+ }
+
+ @Test
+ fun `loaded post from explicitely not trusted sone is not visible`() {
+ remoteSone.identity.setTrust(localSone.identity as OwnIdentity, Trust(-1, null, null))
+ val post = createPost(sone = remoteSone)
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(false))
+ }
+
+ @Test
+ fun `loaded post from implicitely untrusted sone is not visible`() {
+ remoteSone.identity.setTrust(localSone.identity as OwnIdentity, Trust(null, -1, null))
+ val post = createPost(sone = remoteSone)
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(false))
+ }
+
+ @Test
+ fun `loaded post from implicitely untrusted but followed sone is visible`() {
+ localSone.friends.add(remoteSone.id)
+ remoteSone.identity.setTrust(localSone.identity as OwnIdentity, Trust(1, -1, null))
+ val post = createPost(sone = remoteSone)
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
+ }
+
+ @Test
+ fun `loaded post from implicitely trusted and followed sone is visible`() {
+ localSone.friends.add(remoteSone.id)
+ remoteSone.identity.setTrust(localSone.identity as OwnIdentity, Trust(null, 1, null))
+ val post = createPost(sone = remoteSone)
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
+ }
+
+ @Test
+ fun `loaded post from followed sone with unknown trust is visible`() {
+ localSone.friends.add(remoteSone.id)
+ remoteSone.identity.setTrust(localSone.identity as OwnIdentity, Trust(null, null, null))
+ val post = createPost(sone = remoteSone)
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
+ }
+
+ @Test
+ fun `loaded post from unfollowed remote sone that is not directed at local sone is not visible`() {
+ val post = createPost(sone = remoteSone)
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(false))
+ }
+
+ @Test
+ fun `loaded post from local sone is visible`() {
+ val post = createPost(sone = localSone)
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
+ }
+
+ @Test
+ fun `loaded post from followed remote sone that is not directed at local sone is visible`() {
+ localSone.friends.add(remoteSone.id)
+ val post = createPost(sone = remoteSone)
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
+ }
+
+ @Test
+ fun `loaded post from remote sone that is directed at local sone is visible`() {
+ val post = createPost(sone = remoteSone, recipient = localSone)
+ assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
+ }
+
+ @Test
+ fun `predicate will correctly recognize visible post`() {
+ val post = createPost(sone = localSone)
+ assertThat(postVisibilityFilter.isVisible(null).test(post), equalTo(true))
+ }
+
+ @Test
+ fun `predicate will correctly recognize not visible post`() {
+ val post = createPost(loaded = false)
+ assertThat(postVisibilityFilter.isVisible(null).test(post), equalTo(false))
+ }
+
+}
private val showAllPosts = createPostVisibilityFilter { _, _ -> true }
private val showNoPosts = createPostVisibilityFilter { _, _ -> false }
-private fun createPostVisibilityFilter(visible: (Sone?, Post) -> Boolean) = object : PostVisibilityFilter() {
+private fun createPostVisibilityFilter(visible: (Sone?, Post) -> Boolean) = object : PostVisibilityFilter {
override fun isPostVisible(sone: Sone?, post: Post) = visible(sone, post)
override fun isVisible(currentSone: Sone?) = Predicate<Post> { p -> p != null && isPostVisible(currentSone, p) }
}
+++ /dev/null
-package net.pterodactylus.sone.notify
-
-import com.google.inject.Guice
-import net.pterodactylus.sone.freenet.wot.OwnIdentity
-import net.pterodactylus.sone.freenet.wot.Trust
-import net.pterodactylus.sone.test.createLocalSone
-import net.pterodactylus.sone.test.createPost
-import net.pterodactylus.sone.test.createRemoteSone
-import net.pterodactylus.sone.test.verifySingletonInstance
-import org.hamcrest.MatcherAssert.assertThat
-import org.hamcrest.Matchers.equalTo
-import org.junit.Test
-
-/**
- * Unit test for [PostVisibilityFilterTest].
- */
-class PostVisibilityFilterTest {
-
- private val postVisibilityFilter = PostVisibilityFilter()
- private val localSone = createLocalSone()
- private val remoteSone = createRemoteSone()
-
- @Test
- fun `post visibility filter is only created once`() {
- val injector = Guice.createInjector()
- injector.verifySingletonInstance<PostVisibilityFilter>()
- }
-
- @Test
- fun `post is not visible if it is not loaded`() {
- val post = createPost(loaded = false)
- assertThat(postVisibilityFilter.isPostVisible(null, post), equalTo(false))
- }
-
- @Test
- fun `loaded post is visible without sone and in the past`() {
- val post = createPost(sone = null)
- assertThat(postVisibilityFilter.isPostVisible(null, post), equalTo(true))
- }
-
- @Test
- fun `loaded post from the future is not visible`() {
- // the offset for the future must be large enough to survive loading freenet.crypt.Util.
- val post = createPost(time = System.currentTimeMillis() + 100000, sone = null)
- assertThat(postVisibilityFilter.isPostVisible(null, post), equalTo(false))
- }
-
- @Test
- fun `loaded post from explicitely not trusted sone is not visible`() {
- remoteSone.identity.setTrust(localSone.identity as OwnIdentity, Trust(-1, null, null))
- val post = createPost(sone = remoteSone)
- assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(false))
- }
-
- @Test
- fun `loaded post from implicitely untrusted sone is not visible`() {
- remoteSone.identity.setTrust(localSone.identity as OwnIdentity, Trust(null, -1, null))
- val post = createPost(sone = remoteSone)
- assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(false))
- }
-
- @Test
- fun `loaded post from implicitely untrusted but followed sone is visible`() {
- localSone.friends.add(remoteSone.id)
- remoteSone.identity.setTrust(localSone.identity as OwnIdentity, Trust(1, -1, null))
- val post = createPost(sone = remoteSone)
- assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
- }
-
- @Test
- fun `loaded post from implicitely trusted and followed sone is visible`() {
- localSone.friends.add(remoteSone.id)
- remoteSone.identity.setTrust(localSone.identity as OwnIdentity, Trust(null, 1, null))
- val post = createPost(sone = remoteSone)
- assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
- }
-
- @Test
- fun `loaded post from followed sone with unknown trust is visible`() {
- localSone.friends.add(remoteSone.id)
- remoteSone.identity.setTrust(localSone.identity as OwnIdentity, Trust(null, null, null))
- val post = createPost(sone = remoteSone)
- assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
- }
-
- @Test
- fun `loaded post from unfollowed remote sone that is not directed at local sone is not visible`() {
- val post = createPost(sone = remoteSone)
- assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(false))
- }
-
- @Test
- fun `loaded post from local sone is visible`() {
- val post = createPost(sone = localSone)
- assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
- }
-
- @Test
- fun `loaded post from followed remote sone that is not directed at local sone is visible`() {
- localSone.friends.add(remoteSone.id)
- val post = createPost(sone = remoteSone)
- assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
- }
-
- @Test
- fun `loaded post from remote sone that is directed at local sone is visible`() {
- val post = createPost(sone = remoteSone, recipient = localSone)
- assertThat(postVisibilityFilter.isPostVisible(localSone, post), equalTo(true))
- }
-
- @Test
- fun `predicate will correctly recognize visible post`() {
- val post = createPost(sone = localSone)
- assertThat(postVisibilityFilter.isVisible(null).test(post), equalTo(true))
- }
-
- @Test
- fun `predicate will correctly recognize not visible post`() {
- val post = createPost(loaded = false)
- assertThat(postVisibilityFilter.isVisible(null).test(post), equalTo(false))
- }
-
-}