From 24a1147058b1a8e4c3021dd61b0b24d4e350eabb Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Tue, 5 Nov 2013 22:44:57 +0100 Subject: [PATCH] Move reply like functionality from Sone to Reply. --- .../java/net/pterodactylus/sone/core/Core.java | 17 --------- .../java/net/pterodactylus/sone/data/Reply.java | 7 ++++ .../java/net/pterodactylus/sone/data/Sone.java | 28 -------------- .../sone/data/impl/DefaultPostReply.java | 23 +++++++++++ .../sone/database/PostReplyDatabase.java | 7 ++++ .../sone/database/memory/MemoryDatabase.java | 44 ++++++++++++++++++++++ .../pterodactylus/sone/fcp/LikeReplyCommand.java | 4 +- .../pterodactylus/sone/template/ReplyAccessor.java | 4 +- .../java/net/pterodactylus/sone/web/LikePage.java | 6 ++- .../net/pterodactylus/sone/web/UnlikePage.java | 6 ++- .../sone/web/ajax/GetLikesAjaxPage.java | 2 +- .../pterodactylus/sone/web/ajax/LikeAjaxPage.java | 6 ++- .../sone/web/ajax/UnlikeAjaxPage.java | 6 ++- .../java/net/pterodactylus/sone/data/Mocks.java | 21 +++++++++++ 14 files changed, 127 insertions(+), 54 deletions(-) diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 0caf03f..6d67c25 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -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 getLikes(PostReply reply) { - Set sones = new HashSet(); - for (Sone sone : getSones()) { - if (sone.getLikedReplyIds().contains(reply.getId())) { - sones.add(sone); - } - } - return sones; - } - - /** * Returns whether the given post is bookmarked. * * @param post diff --git a/src/main/java/net/pterodactylus/sone/data/Reply.java b/src/main/java/net/pterodactylus/sone/data/Reply.java index c660f27..510b81f 100644 --- a/src/main/java/net/pterodactylus/sone/data/Reply.java +++ b/src/main/java/net/pterodactylus/sone/data/Reply.java @@ -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> extends Identified { */ public boolean isKnown(); + void like(Sone localSone); + void unlike(Sone localSone); + + boolean isLiked(Sone sone); + Set getLikes(); + Modifier modify(); interface Modifier { diff --git a/src/main/java/net/pterodactylus/sone/data/Sone.java b/src/main/java/net/pterodactylus/sone/data/Sone.java index 44929c6..63b6e05 100644 --- a/src/main/java/net/pterodactylus/sone/data/Sone.java +++ b/src/main/java/net/pterodactylus/sone/data/Sone.java @@ -424,34 +424,6 @@ public interface Sone extends Identified, Fingerprintable, Comparable { Sone setLikeReplyIds(Set 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 diff --git a/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostReply.java b/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostReply.java index 41e64b0..5af6f42 100644 --- a/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostReply.java +++ b/src/main/java/net/pterodactylus/sone/data/impl/DefaultPostReply.java @@ -17,8 +17,11 @@ 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 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 getLikes() { + return database.getLikes(this); + } + + @Override public Modifier modify() { return new Modifier() { private boolean known = isKnown(); diff --git a/src/main/java/net/pterodactylus/sone/database/PostReplyDatabase.java b/src/main/java/net/pterodactylus/sone/database/PostReplyDatabase.java index 1b8fbe5..5bcbf29 100644 --- a/src/main/java/net/pterodactylus/sone/database/PostReplyDatabase.java +++ b/src/main/java/net/pterodactylus/sone/database/PostReplyDatabase.java @@ -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 getLikes(PostReply postReply); + } diff --git a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java index 01b7839..691b604 100644 --- a/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java +++ b/src/main/java/net/pterodactylus/sone/database/memory/MemoryDatabase.java @@ -95,6 +95,8 @@ public class MemoryDatabase extends AbstractService implements Database { /** All post replies by their ID. */ private final Map allPostReplies = new HashMap(); + private final SetMultimap likedPostRepliesBySone = HashMultimap.create(); + private final SetMultimap postReplyLikingSones = HashMultimap.create(); /** Replies sorted by Sone. */ private final SortedSetMultimap sonePostReplies = TreeMultimap.create(new Comparator() { @@ -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 getLikes(PostReply postReply) { + lock.readLock().lock(); + try { + return from(postReplyLikingSones.get(postReply.getId())).transform(getSone()).transformAndConcat(this.unwrap()).toSet(); + } finally { + lock.readLock().unlock(); + } + } + // // POSTREPLYSTORE METHODS // diff --git a/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java b/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java index ef8efc8..4e0c3fe 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java @@ -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()); } } diff --git a/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java b/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java index 7e81eb7..e81c819 100644 --- a/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java @@ -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")) { diff --git a/src/main/java/net/pterodactylus/sone/web/LikePage.java b/src/main/java/net/pterodactylus/sone/web/LikePage.java index 970b4c5..98777f8 100644 --- a/src/main/java/net/pterodactylus/sone/web/LikePage.java +++ b/src/main/java/net/pterodactylus/sone/web/LikePage.java @@ -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 = webInterface.getCore().getDatabase().getPostReply(id); + if (postReply.isPresent()) { + postReply.get().like(currentSone); + } } throw new RedirectException(returnPage); } diff --git a/src/main/java/net/pterodactylus/sone/web/UnlikePage.java b/src/main/java/net/pterodactylus/sone/web/UnlikePage.java index 48e5ab7..fd9f4b1 100644 --- a/src/main/java/net/pterodactylus/sone/web/UnlikePage.java +++ b/src/main/java/net/pterodactylus/sone/web/UnlikePage.java @@ -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 = webInterface.getCore().getDatabase().getPostReply(id); + if (postReply.isPresent()) { + postReply.get().unlike(currentSone); + } } throw new RedirectException(returnPage); } diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java index 058b142..f4bf648 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java @@ -75,7 +75,7 @@ public class GetLikesAjaxPage extends JsonPage { if (!reply.isPresent()) { return createErrorJsonObject("invalid-reply-id"); } - Set sones = webInterface.getCore().getLikes(reply.get()); + Set sones = reply.get().getLikes(); return createSuccessJsonObject().put("likes", sones.size()).put("sones", getSones(sones)); } return createErrorJsonObject("invalid-type"); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/LikeAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/LikeAjaxPage.java index ceeaf16..84a93e3 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/LikeAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/LikeAjaxPage.java @@ -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 = webInterface.getCore().getDatabase().getPostReply(id); + if (postReply.isPresent()) { + postReply.get().like(currentSone); + } webInterface.getCore().touchConfiguration(); } else { return createErrorJsonObject("invalid-type"); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.java index 5ac0ca0..bd5f91b 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.java @@ -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 = webInterface.getCore().getDatabase().getPostReply(id); + if (postReply.isPresent()) { + postReply.get().unlike(currentSone); + } webInterface.getCore().touchConfiguration(); } else { return createErrorJsonObject("invalid-type"); diff --git a/src/test/java/net/pterodactylus/sone/data/Mocks.java b/src/test/java/net/pterodactylus/sone/data/Mocks.java index 4b60c1a..f1b0a09 100644 --- a/src/test/java/net/pterodactylus/sone/data/Mocks.java +++ b/src/test/java/net/pterodactylus/sone/data/Mocks.java @@ -64,6 +64,7 @@ public class Mocks { private final Multimap postReplies = create(); private final Multimap directedPosts = create(); private final SetMultimap postLikingSones = HashMultimap.create(); + private final SetMultimap 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() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + postReplyLikingSones.put(postReply, (Sone) invocation.getArguments()[0]); + return null; + } + }).when(postReply).like(Matchers.any()); + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + postReplyLikingSones.remove(postReply, invocation.getArguments()[0]); + return null; + } + }).when(postReply).unlike(Matchers.any()); + when(postReply.getLikes()).thenAnswer(new Answer>() { + @Override + public Set answer(InvocationOnMock invocation) throws Throwable { + return postReplyLikingSones.get(postReply); + } + }); return postReply; } } -- 2.7.4