Move reply like functionality from Sone to Reply.
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Tue, 5 Nov 2013 21:44:57 +0000 (22:44 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 28 Feb 2014 21:25:54 +0000 (22:25 +0100)
14 files changed:
src/main/java/net/pterodactylus/sone/core/Core.java
src/main/java/net/pterodactylus/sone/data/Reply.java
src/main/java/net/pterodactylus/sone/data/Sone.java
src/main/java/net/pterodactylus/sone/data/impl/DefaultPostReply.java
src/main/java/net/pterodactylus/sone/database/PostReplyDatabase.java
src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java
src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java
src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java
src/main/java/net/pterodactylus/sone/web/LikePage.java
src/main/java/net/pterodactylus/sone/web/UnlikePage.java
src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java
src/main/java/net/pterodactylus/sone/web/ajax/LikeAjaxPage.java
src/main/java/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.java
src/test/java/net/pterodactylus/sone/data/Mocks.java

index 0caf03f..6d67c25 100644 (file)
@@ -413,23 +413,6 @@ public class Core extends AbstractService implements SoneProvider {
        }
 
        /**
-        * Returns all Sones that have liked the given reply.
-        *
-        * @param reply
-        *              The reply to get the liking Sones for
-        * @return The Sones that like the given reply
-        */
-       public Set<Sone> getLikes(PostReply reply) {
-               Set<Sone> sones = new HashSet<Sone>();
-               for (Sone sone : getSones()) {
-                       if (sone.getLikedReplyIds().contains(reply.getId())) {
-                               sones.add(sone);
-                       }
-               }
-               return sones;
-       }
-
-       /**
         * Returns whether the given post is bookmarked.
         *
         * @param post
index c660f27..510b81f 100644 (file)
@@ -18,6 +18,7 @@
 package net.pterodactylus.sone.data;
 
 import java.util.Comparator;
+import java.util.Set;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Predicate;
@@ -92,6 +93,12 @@ public interface Reply<T extends Reply<T>> extends Identified {
         */
        public boolean isKnown();
 
+       void like(Sone localSone);
+       void unlike(Sone localSone);
+
+       boolean isLiked(Sone sone);
+       Set<Sone> getLikes();
+
        Modifier<T> modify();
 
        interface Modifier<T> {
index 44929c6..63b6e05 100644 (file)
@@ -424,34 +424,6 @@ public interface Sone extends Identified, Fingerprintable, Comparable<Sone> {
        Sone setLikeReplyIds(Set<String> likedReplyIds);
 
        /**
-        * Checks whether the given reply ID is liked by this Sone.
-        *
-        * @param replyId
-        *              The ID of the reply
-        * @return {@code true} if this Sone likes the given reply, {@code false}
-        *         otherwise
-        */
-       boolean isLikedReplyId(String replyId);
-
-       /**
-        * Adds the given reply ID to the list of replies this Sone likes.
-        *
-        * @param replyId
-        *              The ID of the reply
-        * @return This Sone (for method chaining)
-        */
-       Sone addLikedReplyId(String replyId);
-
-       /**
-        * Removes the given post ID from the list of replies this Sone likes.
-        *
-        * @param replyId
-        *              The ID of the reply
-        * @return This Sone (for method chaining)
-        */
-       Sone removeLikedReplyId(String replyId);
-
-       /**
         * Returns the root album that contains all visible albums of this Sone.
         *
         * @return The root album of this Sone
index 41e64b0..5af6f42 100644 (file)
 
 package net.pterodactylus.sone.data.impl;
 
+import java.util.Set;
+
 import net.pterodactylus.sone.data.Post;
 import net.pterodactylus.sone.data.PostReply;
+import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.database.Database;
 
 import com.google.common.base.Optional;
@@ -73,6 +76,26 @@ public class DefaultPostReply extends DefaultReply<PostReply> implements PostRep
        }
 
        @Override
+       public void like(Sone localSone) {
+               database.likePostReply(this, localSone);
+       }
+
+       @Override
+       public void unlike(Sone localSone) {
+               database.unlikePostReply(this, localSone);
+       }
+
+       @Override
+       public boolean isLiked(Sone sone) {
+               return database.isLiked(this, sone);
+       }
+
+       @Override
+       public Set<Sone> getLikes() {
+               return database.getLikes(this);
+       }
+
+       @Override
        public Modifier<PostReply> modify() {
                return new Modifier<PostReply>() {
                        private boolean known = isKnown();
index 1b8fbe5..5bcbf29 100644 (file)
@@ -19,6 +19,7 @@ package net.pterodactylus.sone.database;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Set;
 
 import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Sone;
@@ -90,4 +91,10 @@ public interface PostReplyDatabase {
         */
        void removePostReplies(Sone sone);
 
+       void likePostReply(PostReply postReply, Sone localSone);
+       void unlikePostReply(PostReply postReply, Sone localSone);
+
+       boolean isLiked(PostReply postReply, Sone sone);
+       Set<Sone> getLikes(PostReply postReply);
+
 }
index 01b7839..691b604 100644 (file)
@@ -95,6 +95,8 @@ public class MemoryDatabase extends AbstractService implements Database {
 
        /** All post replies by their ID. */
        private final Map<String, PostReply> allPostReplies = new HashMap<String, PostReply>();
+       private final SetMultimap<String, String> likedPostRepliesBySone = HashMultimap.create();
+       private final SetMultimap<String, String> postReplyLikingSones = HashMultimap.create();
 
        /** Replies sorted by Sone. */
        private final SortedSetMultimap<String, PostReply> sonePostReplies = TreeMultimap.create(new Comparator<String>() {
@@ -442,6 +444,48 @@ public class MemoryDatabase extends AbstractService implements Database {
                }
        }
 
+       @Override
+       public void likePostReply(PostReply postReply, Sone localSone) {
+               lock.writeLock().lock();
+               try {
+                       likedPostRepliesBySone.put(localSone.getId(), postReply.getId());
+                       postReplyLikingSones.put(postReply.getId(), localSone.getId());
+               } finally {
+                       lock.writeLock().unlock();
+               }
+       }
+
+       @Override
+       public void unlikePostReply(PostReply postReply, Sone localSone) {
+               lock.writeLock().lock();
+               try {
+                       likedPostRepliesBySone.remove(localSone.getId(), postReply.getId());
+                       postReplyLikingSones.remove(postReply.getId(), localSone.getId());
+               } finally {
+                       lock.writeLock().unlock();
+               }
+       }
+
+       @Override
+       public boolean isLiked(PostReply postReply, Sone sone) {
+               lock.readLock().lock();
+               try {
+                       return postReplyLikingSones.containsEntry(postReply.getId(), sone.getId());
+               } finally {
+                       lock.readLock().unlock();
+               }
+       }
+
+       @Override
+       public Set<Sone> getLikes(PostReply postReply) {
+               lock.readLock().lock();
+               try {
+                       return from(postReplyLikingSones.get(postReply.getId())).transform(getSone()).transformAndConcat(this.<Sone>unwrap()).toSet();
+               } finally {
+                       lock.readLock().unlock();
+               }
+       }
+
        //
        // POSTREPLYSTORE METHODS
        //
index ef8efc8..4e0c3fe 100644 (file)
@@ -46,8 +46,8 @@ public class LikeReplyCommand extends AbstractSoneCommand {
        public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException {
                PostReply reply = getReply(parameters, "Reply");
                Sone sone = getMandatoryLocalSone(parameters, "Sone");
-               sone.addLikedReplyId(reply.getId());
-               return new Response("ReplyLiked", new SimpleFieldSetBuilder().put("LikeCount", getCore().getLikes(reply).size()).get());
+               reply.like(sone);
+               return new Response("ReplyLiked", new SimpleFieldSetBuilder().put("LikeCount", reply.getLikes().size()).get());
        }
 
 }
index 7e81eb7..e81c819 100644 (file)
@@ -50,10 +50,10 @@ public class ReplyAccessor extends ReflectionAccessor {
        public Object get(TemplateContext templateContext, Object object, String member) {
                PostReply reply = (PostReply) object;
                if ("likes".equals(member)) {
-                       return core.getLikes(reply);
+                       return reply.getLikes();
                } else if (member.equals("liked")) {
                        Sone currentSone = (Sone) templateContext.get("currentSone");
-                       return (currentSone != null) && (currentSone.isLikedReplyId(reply.getId()));
+                       return (currentSone != null) && reply.isLiked(currentSone);
                } else if (member.equals("new")) {
                        return !reply.isKnown();
                } else if (member.equals("loaded")) {
index 970b4c5..98777f8 100644 (file)
@@ -18,6 +18,7 @@
 package net.pterodactylus.sone.web;
 
 import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.web.page.FreenetRequest;
 import net.pterodactylus.util.template.Template;
@@ -63,7 +64,10 @@ public class LikePage extends SoneTemplatePage {
                                        post.get().like(currentSone);
                                }
                        } else if ("reply".equals(type)) {
-                               currentSone.addLikedReplyId(id);
+                               Optional<PostReply> postReply = webInterface.getCore().getDatabase().getPostReply(id);
+                               if (postReply.isPresent()) {
+                                       postReply.get().like(currentSone);
+                               }
                        }
                        throw new RedirectException(returnPage);
                }
index 48e5ab7..fd9f4b1 100644 (file)
@@ -18,6 +18,7 @@
 package net.pterodactylus.sone.web;
 
 import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.web.page.FreenetRequest;
 import net.pterodactylus.util.template.Template;
@@ -63,7 +64,10 @@ public class UnlikePage extends SoneTemplatePage {
                                        post.get().unlike(currentSone);
                                }
                        } else if ("reply".equals(type)) {
-                               currentSone.removeLikedReplyId(id);
+                               Optional<PostReply> postReply = webInterface.getCore().getDatabase().getPostReply(id);
+                               if (postReply.isPresent()) {
+                                       postReply.get().unlike(currentSone);
+                               }
                        }
                        throw new RedirectException(returnPage);
                }
index 058b142..f4bf648 100644 (file)
@@ -75,7 +75,7 @@ public class GetLikesAjaxPage extends JsonPage {
                        if (!reply.isPresent()) {
                                return createErrorJsonObject("invalid-reply-id");
                        }
-                       Set<Sone> sones = webInterface.getCore().getLikes(reply.get());
+                       Set<Sone> sones = reply.get().getLikes();
                        return createSuccessJsonObject().put("likes", sones.size()).put("sones", getSones(sones));
                }
                return createErrorJsonObject("invalid-type");
index ceeaf16..84a93e3 100644 (file)
@@ -18,6 +18,7 @@
 package net.pterodactylus.sone.web.ajax;
 
 import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.web.WebInterface;
 import net.pterodactylus.sone.web.page.FreenetRequest;
@@ -59,7 +60,10 @@ public class LikeAjaxPage extends JsonPage {
                        }
                        webInterface.getCore().touchConfiguration();
                } else if ("reply".equals(type)) {
-                       currentSone.addLikedReplyId(id);
+                       Optional<PostReply> postReply = webInterface.getCore().getDatabase().getPostReply(id);
+                       if (postReply.isPresent()) {
+                               postReply.get().like(currentSone);
+                       }
                        webInterface.getCore().touchConfiguration();
                } else {
                        return createErrorJsonObject("invalid-type");
index 5ac0ca0..bd5f91b 100644 (file)
@@ -18,6 +18,7 @@
 package net.pterodactylus.sone.web.ajax;
 
 import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.PostReply;
 import net.pterodactylus.sone.data.Sone;
 import net.pterodactylus.sone.web.WebInterface;
 import net.pterodactylus.sone.web.page.FreenetRequest;
@@ -59,7 +60,10 @@ public class UnlikeAjaxPage extends JsonPage {
                        }
                        webInterface.getCore().touchConfiguration();
                } else if ("reply".equals(type)) {
-                       currentSone.removeLikedReplyId(id);
+                       Optional<PostReply> postReply = webInterface.getCore().getDatabase().getPostReply(id);
+                       if (postReply.isPresent()) {
+                               postReply.get().unlike(currentSone);
+                       }
                        webInterface.getCore().touchConfiguration();
                } else {
                        return createErrorJsonObject("invalid-type");
index 4b60c1a..f1b0a09 100644 (file)
@@ -64,6 +64,7 @@ public class Mocks {
        private final Multimap<Post, PostReply> postReplies = create();
        private final Multimap<String, Post> directedPosts = create();
        private final SetMultimap<Post, Sone> postLikingSones = HashMultimap.create();
+       private final SetMultimap<PostReply, Sone> postReplyLikingSones = HashMultimap.create();
        public final Database database;
        public final Core core;
 
@@ -323,6 +324,26 @@ public class Mocks {
                        if (text.isPresent()) {
                                when(postReply.getText()).thenReturn(text.get());
                        }
+                       doAnswer(new Answer<Void>() {
+                               @Override
+                               public Void answer(InvocationOnMock invocation) throws Throwable {
+                                       postReplyLikingSones.put(postReply, (Sone) invocation.getArguments()[0]);
+                                       return null;
+                               }
+                       }).when(postReply).like(Matchers.<Sone>any());
+                       doAnswer(new Answer<Void>() {
+                               @Override
+                               public Void answer(InvocationOnMock invocation) throws Throwable {
+                                       postReplyLikingSones.remove(postReply, invocation.getArguments()[0]);
+                                       return null;
+                               }
+                       }).when(postReply).unlike(Matchers.<Sone>any());
+                       when(postReply.getLikes()).thenAnswer(new Answer<Set<Sone>>() {
+                               @Override
+                               public Set<Sone> answer(InvocationOnMock invocation) throws Throwable {
+                                       return postReplyLikingSones.get(postReply);
+                               }
+                       });
                        return postReply;
                }
        }