From: David ‘Bombe’ Roden Date: Tue, 4 Oct 2011 04:13:58 +0000 (+0200) Subject: Merge branch 'release-0.7.2' X-Git-Tag: 0.7.2 X-Git-Url: https://git.pterodactylus.net/?a=commitdiff_plain;h=ef64eab29af1738adea8df9ad4fe2e6e55f0b2c7;hp=05f968bfa954585e942bbaff078d8932429f3175;p=Sone.git Merge branch 'release-0.7.2' --- diff --git a/pom.xml b/pom.xml index fa78bcb..35203cf 100644 --- a/pom.xml +++ b/pom.xml @@ -2,12 +2,12 @@ 4.0.0 net.pterodactylus sone - 0.7.1 + 0.7.2 net.pterodactylus utils - 0.11 + 0.11.1 junit diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 8aac5d7..ee5ec87 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -38,6 +38,7 @@ import net.pterodactylus.sone.data.Album; import net.pterodactylus.sone.data.Client; import net.pterodactylus.sone.data.Image; import net.pterodactylus.sone.data.Post; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Profile; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; @@ -173,7 +174,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis private Set knownPosts = new HashSet(); /** All replies. */ - private Map replies = new HashMap(); + private Map replies = new HashMap(); /** All new replies. */ private Set newReplies = new HashSet(); @@ -676,7 +677,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis * The ID of the reply to get * @return The reply */ - public Reply getReply(String replyId) { + public PostReply getReply(String replyId) { return getReply(replyId, true); } @@ -692,11 +693,11 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis * to return {@code null} if no reply can be found * @return The reply, or {@code null} if there is no such reply */ - public Reply getReply(String replyId, boolean create) { + public PostReply getReply(String replyId, boolean create) { synchronized (replies) { - Reply reply = replies.get(replyId); + PostReply reply = replies.get(replyId); if (create && (reply == null)) { - reply = new Reply(replyId); + reply = new PostReply(replyId); replies.put(replyId, reply); } return reply; @@ -710,11 +711,11 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis * The post to get all replies for * @return All replies for the given post */ - public List getReplies(Post post) { + public List getReplies(Post post) { Set sones = getSones(); - List replies = new ArrayList(); + List replies = new ArrayList(); for (Sone sone : sones) { - for (Reply reply : sone.getReplies()) { + for (PostReply reply : sone.getReplies()) { if (reply.getPost().equals(post)) { replies.add(reply); } @@ -762,7 +763,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis * The reply to get the liking Sones for * @return The Sones that like the given reply */ - public Set getLikes(Reply reply) { + public Set getLikes(PostReply reply) { Set sones = new HashSet(); for (Sone sone : getSones()) { if (sone.getLikedReplyIds().contains(reply.getId())) { @@ -1204,16 +1205,16 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis } synchronized (replies) { if (!soneRescueMode) { - for (Reply reply : storedSone.getReplies()) { + for (PostReply reply : storedSone.getReplies()) { replies.remove(reply.getId()); if (!sone.getReplies().contains(reply)) { coreListenerManager.fireReplyRemoved(reply); } } } - Set storedReplies = storedSone.getReplies(); + Set storedReplies = storedSone.getReplies(); synchronized (newReplies) { - for (Reply reply : sone.getReplies()) { + for (PostReply reply : sone.getReplies()) { reply.setSone(storedSone); if (!storedReplies.contains(reply) && !knownReplies.contains(reply.getId())) { newReplies.add(reply.getId()); @@ -1249,7 +1250,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis for (Post post : sone.getPosts()) { storedSone.addPost(post); } - for (Reply reply : sone.getReplies()) { + for (PostReply reply : sone.getReplies()) { storedSone.addReply(reply); } for (String likedPostId : sone.getLikedPostIds()) { @@ -1395,7 +1396,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis } /* load replies. */ - Set replies = new HashSet(); + Set replies = new HashSet(); while (true) { String replyPrefix = sonePrefix + "/Replies/" + replies.size(); String replyId = configuration.getStringValue(replyPrefix + "/ID").getValue(null); @@ -1528,7 +1529,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis } } synchronized (newReplies) { - for (Reply reply : replies) { + for (PostReply reply : replies) { knownReplies.add(reply.getId()); } } @@ -1718,7 +1719,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis * The text of the reply * @return The created reply */ - public Reply createReply(Sone sone, Post post, String text) { + public PostReply createReply(Sone sone, Post post, String text) { return createReply(sone, post, System.currentTimeMillis(), text); } @@ -1735,12 +1736,12 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis * The text of the reply * @return The created reply */ - public Reply createReply(Sone sone, Post post, long time, String text) { + public PostReply createReply(Sone sone, Post post, long time, String text) { if (!isLocalSone(sone)) { logger.log(Level.FINE, "Tried to create reply for non-local Sone: %s", sone); return null; } - final Reply reply = new Reply(sone, post, System.currentTimeMillis(), text); + final PostReply reply = new PostReply(sone, post, System.currentTimeMillis(), text); synchronized (replies) { replies.put(reply.getId(), reply); } @@ -1769,7 +1770,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis * @param reply * The reply to delete */ - public void deleteReply(Reply reply) { + public void deleteReply(PostReply reply) { Sone sone = reply.getSone(); if (!isLocalSone(sone)) { logger.log(Level.FINE, "Tried to delete non-local reply: %s", reply); @@ -1793,7 +1794,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis * @param reply * The reply to mark as known */ - public void markReplyKnown(Reply reply) { + public void markReplyKnown(PostReply reply) { synchronized (newReplies) { if (newReplies.remove(reply.getId())) { knownReplies.add(reply.getId()); @@ -2028,8 +2029,6 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis logger.log(Level.INFO, "Saving Sone: %s", sone); try { - ((OwnIdentity) sone.getIdentity()).setProperty("Sone.LatestEdition", String.valueOf(sone.getLatestEdition())); - /* save Sone into configuration. */ String sonePrefix = "Sone/" + sone.getId(); configuration.getLongValue(sonePrefix + "/Time").setValue(sone.getTime()); @@ -2066,7 +2065,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis /* save replies. */ int replyCounter = 0; - for (Reply reply : sone.getReplies()) { + for (PostReply reply : sone.getReplies()) { String replyPrefix = sonePrefix + "/Replies/" + replyCounter++; configuration.getStringValue(replyPrefix + "/ID").setValue(reply.getId()); configuration.getStringValue(replyPrefix + "/Post/ID").setValue(reply.getPost().getId()); @@ -2097,7 +2096,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis configuration.getStringValue(sonePrefix + "/Friends/" + friendCounter + "/ID").setValue(null); /* save albums. first, collect in a flat structure, top-level first. */ - List albums = Sone.flattenAlbums(sone.getAlbums()); + List albums = sone.getAllAlbums(); int albumCounter = 0; for (Album album : albums) { @@ -2135,6 +2134,9 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis configuration.getBooleanValue(sonePrefix + "/Options/EnableSoneInsertNotifications").setValue(sone.getOptions().getBooleanOption("EnableSoneInsertNotifications").getReal()); configuration.save(); + + ((OwnIdentity) sone.getIdentity()).setProperty("Sone.LatestEdition", String.valueOf(sone.getLatestEdition())); + logger.log(Level.INFO, "Sone %s saved.", sone); } catch (ConfigurationException ce1) { logger.log(Level.WARNING, "Could not save Sone: " + sone, ce1); @@ -2161,6 +2163,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis configuration.getIntValue("Option/InsertionDelay").setValue(options.getIntegerOption("InsertionDelay").getReal()); configuration.getIntValue("Option/PostsPerPage").setValue(options.getIntegerOption("PostsPerPage").getReal()); configuration.getIntValue("Option/CharactersPerPost").setValue(options.getIntegerOption("CharactersPerPost").getReal()); + configuration.getIntValue("Option/PostCutOffLength").setValue(options.getIntegerOption("PostCutOffLength").getReal()); configuration.getBooleanValue("Option/RequireFullAccess").setValue(options.getBooleanOption("RequireFullAccess").getReal()); configuration.getIntValue("Option/PositiveTrust").setValue(options.getIntegerOption("PositiveTrust").getReal()); configuration.getIntValue("Option/NegativeTrust").setValue(options.getIntegerOption("NegativeTrust").getReal()); @@ -2234,7 +2237,8 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis })); options.addIntegerOption("PostsPerPage", new DefaultOption(10, new IntegerRangeValidator(1, Integer.MAX_VALUE))); - options.addIntegerOption("CharactersPerPost", new DefaultOption(200, new OrValidator(new IntegerRangeValidator(50, Integer.MAX_VALUE), new EqualityValidator(-1)))); + options.addIntegerOption("CharactersPerPost", new DefaultOption(400, new OrValidator(new IntegerRangeValidator(50, Integer.MAX_VALUE), new EqualityValidator(-1)))); + options.addIntegerOption("PostCutOffLength", new DefaultOption(200, new OrValidator(new IntegerRangeValidator(50, Integer.MAX_VALUE), new EqualityValidator(-1)))); options.addBooleanOption("RequireFullAccess", new DefaultOption(false)); options.addIntegerOption("PositiveTrust", new DefaultOption(75, new IntegerRangeValidator(0, 100))); options.addIntegerOption("NegativeTrust", new DefaultOption(-25, new IntegerRangeValidator(-100, 100))); @@ -2274,6 +2278,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis loadConfigurationValue("InsertionDelay"); loadConfigurationValue("PostsPerPage"); loadConfigurationValue("CharactersPerPost"); + loadConfigurationValue("PostCutOffLength"); options.getBooleanOption("RequireFullAccess").set(configuration.getBooleanValue("Option/RequireFullAccess").getValue(null)); loadConfigurationValue("PositiveTrust"); loadConfigurationValue("NegativeTrust"); @@ -2453,7 +2458,7 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis } synchronized (replies) { synchronized (newReplies) { - for (Reply reply : sone.getReplies()) { + for (PostReply reply : sone.getReplies()) { replies.remove(reply.getId()); newReplies.remove(reply.getId()); coreListenerManager.fireReplyRemoved(reply); @@ -2676,6 +2681,39 @@ public class Core extends AbstractService implements IdentityListener, UpdateLis } /** + * Returns the number of characters the shortened post should have. + * + * @return The number of characters of the snippet + */ + public int getPostCutOffLength() { + return options.getIntegerOption("PostCutOffLength").get(); + } + + /** + * Validates the number of characters after which to cut off the post. + * + * @param postCutOffLength + * The number of characters of the snippet + * @return {@code true} if the number of characters of the snippet is + * valid, {@code false} otherwise + */ + public boolean validatePostCutOffLength(Integer postCutOffLength) { + return options.getIntegerOption("PostCutOffLength").validate(postCutOffLength); + } + + /** + * Sets the number of characters the shortened post should have. + * + * @param postCutOffLength + * The number of characters of the snippet + * @return This preferences + */ + public Preferences setPostCutOffLength(Integer postCutOffLength) { + options.getIntegerOption("PostCutOffLength").set(postCutOffLength); + return this; + } + + /** * Returns whether Sone requires full access to be even visible. * * @return {@code true} if Sone requires full access, {@code false} diff --git a/src/main/java/net/pterodactylus/sone/core/CoreListener.java b/src/main/java/net/pterodactylus/sone/core/CoreListener.java index 1658745..2e7b337 100644 --- a/src/main/java/net/pterodactylus/sone/core/CoreListener.java +++ b/src/main/java/net/pterodactylus/sone/core/CoreListener.java @@ -21,7 +21,7 @@ import java.util.EventListener; import net.pterodactylus.sone.data.Image; import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.util.version.Version; @@ -55,7 +55,7 @@ public interface CoreListener extends EventListener { * @param reply * The new reply */ - public void newReplyFound(Reply reply); + public void newReplyFound(PostReply reply); /** * Notifies a listener that the given Sone is now marked as known. @@ -79,7 +79,7 @@ public interface CoreListener extends EventListener { * @param reply * The known reply */ - public void markReplyKnown(Reply reply); + public void markReplyKnown(PostReply reply); /** * Notifies a listener that the given Sone was removed. @@ -103,7 +103,7 @@ public interface CoreListener extends EventListener { * @param reply * The removed reply */ - public void replyRemoved(Reply reply); + public void replyRemoved(PostReply reply); /** * Notifies a listener when a Sone was locked. diff --git a/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java b/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java index 5748ffc..9951ccd 100644 --- a/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java +++ b/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java @@ -19,7 +19,7 @@ package net.pterodactylus.sone.core; import net.pterodactylus.sone.data.Image; import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.util.event.AbstractListenerManager; import net.pterodactylus.util.version.Version; @@ -74,11 +74,11 @@ public class CoreListenerManager extends AbstractListenerManager replies = new HashSet(); + Set replies = new HashSet(); if (repliesXml == null) { /* TODO - mark Sone as bad. */ logger.log(Level.WARNING, "Downloaded Sone %s has no replies!", new Object[] { sone }); @@ -442,7 +442,7 @@ public class SoneDownloader extends AbstractService { String id = albumXml.getValue("id", null); String parentId = albumXml.getValue("parent", null); String title = albumXml.getValue("title", null); - String description = albumXml.getValue("description", null); + String description = albumXml.getValue("description", ""); String albumImageId = albumXml.getValue("album-image", null); if ((id == null) || (title == null) || (description == null)) { logger.log(Level.WARNING, "Downloaded Sone %s contains invalid album!", new Object[] { sone }); @@ -456,7 +456,7 @@ public class SoneDownloader extends AbstractService { return null; } } - Album album = core.getAlbum(id).setSone(sone).setTitle(title).setDescription(description).setAlbumImage(albumImageId); + Album album = core.getAlbum(id).setSone(sone).setTitle(title).setDescription(description); if (parent != null) { parent.addAlbum(album); } else { @@ -489,6 +489,7 @@ public class SoneDownloader extends AbstractService { album.addImage(image); } } + album.setAlbumImage(albumImageId); } } diff --git a/src/main/java/net/pterodactylus/sone/core/SoneInserter.java b/src/main/java/net/pterodactylus/sone/core/SoneInserter.java index 44f8bbc..eb74dc0 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneInserter.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneInserter.java @@ -29,6 +29,7 @@ import java.util.logging.Logger; import net.pterodactylus.sone.core.Core.SoneStatus; import net.pterodactylus.sone.data.Post; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.StringBucket; @@ -299,10 +300,10 @@ public class SoneInserter extends AbstractService { soneProperties.put("insertUri", sone.getInsertUri()); soneProperties.put("profile", sone.getProfile()); soneProperties.put("posts", new ListBuilder(new ArrayList(sone.getPosts())).sort(Post.TIME_COMPARATOR).get()); - soneProperties.put("replies", new ListBuilder(new ArrayList(sone.getReplies())).sort(new ReverseComparator(Reply.TIME_COMPARATOR)).get()); + soneProperties.put("replies", new ListBuilder(new ArrayList(sone.getReplies())).sort(new ReverseComparator>(Reply.TIME_COMPARATOR)).get()); soneProperties.put("likedPostIds", new HashSet(sone.getLikedPostIds())); soneProperties.put("likedReplyIds", new HashSet(sone.getLikedReplyIds())); - soneProperties.put("albums", Sone.flattenAlbums(sone.getAlbums())); + soneProperties.put("albums", sone.getAllAlbums()); } // diff --git a/src/main/java/net/pterodactylus/sone/data/PostReply.java b/src/main/java/net/pterodactylus/sone/data/PostReply.java new file mode 100644 index 0000000..3222d9d --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/data/PostReply.java @@ -0,0 +1,117 @@ +/* + * Sone - PostReply.java - Copyright © 2010–2011 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.data; + +import java.util.UUID; + +/** + * A reply is like a {@link Post} but can never be posted on its own, it always + * refers to another {@link Post}. + * + * @author David ‘Bombe’ Roden + */ +public class PostReply extends Reply { + + /** The Post this reply refers to. */ + private volatile Post post; + + /** + * Creates a new reply. + * + * @param id + * The ID of the reply + */ + public PostReply(String id) { + this(id, null, null, 0, null); + } + + /** + * Creates a new reply. + * + * @param sone + * The sone that posted the reply + * @param post + * The post to reply to + * @param text + * The text of the reply + */ + public PostReply(Sone sone, Post post, String text) { + this(sone, post, System.currentTimeMillis(), text); + } + + /** + * Creates a new reply- + * + * @param sone + * The sone that posted the reply + * @param post + * The post to reply to + * @param time + * The time of the reply + * @param text + * The text of the reply + */ + public PostReply(Sone sone, Post post, long time, String text) { + this(UUID.randomUUID().toString(), sone, post, time, text); + } + + /** + * Creates a new reply- + * + * @param sone + * The sone that posted the reply + * @param id + * The ID of the reply + * @param post + * The post to reply to + * @param time + * The time of the reply + * @param text + * The text of the reply + */ + public PostReply(String id, Sone sone, Post post, long time, String text) { + super(id, sone, time, text); + this.post = post; + } + + // + // ACCESSORS + // + + /** + * Returns the post this reply refers to. + * + * @return The post this reply refers to + */ + public Post getPost() { + return post; + } + + /** + * Sets the post this reply refers to. + * + * @param post + * The post this reply refers to + * @return This reply (for method chaining) + */ + public PostReply setPost(Post post) { + this.post = post; + return this; + } + +} diff --git a/src/main/java/net/pterodactylus/sone/data/Reply.java b/src/main/java/net/pterodactylus/sone/data/Reply.java index 2dacfbe..780fe69 100644 --- a/src/main/java/net/pterodactylus/sone/data/Reply.java +++ b/src/main/java/net/pterodactylus/sone/data/Reply.java @@ -1,5 +1,5 @@ /* - * Sone - Reply.java - Copyright © 2010 David Roden + * Sone - Reply.java - Copyright © 2011 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 @@ -23,42 +23,46 @@ import java.util.UUID; import net.pterodactylus.util.filter.Filter; /** - * A reply is like a {@link Post} but can never be posted on its own, it always - * refers to another {@link Post}. + * Abstract base class for all replies. * + * @param + * The type of the reply * @author David ‘Bombe’ Roden */ -public class Reply { +public abstract class Reply> { /** Comparator that sorts replies ascending by time. */ - public static final Comparator TIME_COMPARATOR = new Comparator() { + public static final Comparator> TIME_COMPARATOR = new Comparator>() { + /** + * {@inheritDoc} + */ @Override - public int compare(Reply leftReply, Reply rightReply) { + public int compare(Reply leftReply, Reply rightReply) { return (int) Math.max(Integer.MIN_VALUE, Math.min(Integer.MAX_VALUE, leftReply.getTime() - rightReply.getTime())); } }; /** Filter for replies with timestamps from the future. */ - public static final Filter FUTURE_REPLIES_FILTER = new Filter() { + public static final Filter> FUTURE_REPLY_FILTER = new Filter>() { + /** + * {@inheritDoc} + */ @Override - public boolean filterObject(Reply reply) { + public boolean filterObject(Reply reply) { return reply.getTime() <= System.currentTimeMillis(); } }; /** The ID of the reply. */ - private final UUID id; + private final String id; - /** The Sone that posted this reply. */ + /** The Sone that created this reply. */ private volatile Sone sone; - /** The Post this reply refers to. */ - private volatile Post post; - /** The time of the reply. */ private volatile long time; @@ -66,78 +70,55 @@ public class Reply { private volatile String text; /** - * Creates a new reply. + * Creates a new reply with the given ID. * * @param id * The ID of the reply */ - public Reply(String id) { - this(id, null, null, 0, null); - } - - /** - * Creates a new reply. - * - * @param sone - * The sone that posted the reply - * @param post - * The post to reply to - * @param text - * The text of the reply - */ - public Reply(Sone sone, Post post, String text) { - this(sone, post, System.currentTimeMillis(), text); + protected Reply(String id) { + this(id, null, 0, null); } /** - * Creates a new reply- + * Creates a new reply with a new random ID. * * @param sone - * The sone that posted the reply - * @param post - * The post to reply to + * The Sone of the reply * @param time * The time of the reply * @param text * The text of the reply */ - public Reply(Sone sone, Post post, long time, String text) { - this(UUID.randomUUID().toString(), sone, post, time, text); + protected Reply(Sone sone, long time, String text) { + this(UUID.randomUUID().toString(), sone, time, text); } /** - * Creates a new reply- + * Creates a new reply. * - * @param sone - * The sone that posted the reply * @param id * The ID of the reply - * @param post - * The post to reply to + * @param sone + * The Sone of the reply * @param time * The time of the reply * @param text * The text of the reply */ - public Reply(String id, Sone sone, Post post, long time, String text) { - this.id = UUID.fromString(id); + protected Reply(String id, Sone sone, long time, String text) { + this.id = id; this.sone = sone; - this.post = post; this.time = time; this.text = text; } - // - // ACCESSORS - // - /** * Returns the ID of the reply. * * @return The ID of the reply */ public String getId() { - return id.toString(); + return id; } /** @@ -156,30 +137,10 @@ public class Reply { * The Sone that posted this reply * @return This reply (for method chaining) */ - public Reply setSone(Sone sone) { + @SuppressWarnings("unchecked") + public T setSone(Sone sone) { this.sone = sone; - return this; - } - - /** - * Returns the post this reply refers to. - * - * @return The post this reply refers to - */ - public Post getPost() { - return post; - } - - /** - * Sets the post this reply refers to. - * - * @param post - * The post this reply refers to - * @return This reply (for method chaining) - */ - public Reply setPost(Post post) { - this.post = post; - return this; + return (T) this; } /** @@ -198,9 +159,10 @@ public class Reply { * The time of this reply (in milliseconds since Jan 1, 1970 UTC) * @return This reply (for method chaining) */ - public Reply setTime(long time) { + @SuppressWarnings("unchecked") + public T setTime(long time) { this.time = time; - return this; + return (T) this; } /** @@ -219,9 +181,10 @@ public class Reply { * The text of this reply * @return This reply (for method chaining) */ - public Reply setText(String text) { + @SuppressWarnings("unchecked") + public T setText(String text) { this.text = text; - return this; + return (T) this; } // @@ -241,10 +204,10 @@ public class Reply { */ @Override public boolean equals(Object object) { - if (!(object instanceof Reply)) { + if (!(object instanceof Reply)) { return false; } - Reply reply = (Reply) object; + Reply reply = (Reply) object; return reply.id.equals(id); } @@ -253,7 +216,7 @@ public class Reply { */ @Override public String toString() { - return getClass().getName() + "[id=" + id + ",sone=" + sone + ",post=" + post + ",time=" + time + ",text=" + text + "]"; + return getClass().getName() + "[id=" + id + ",sone=" + sone + ",time=" + time + ",text=" + text + "]"; } } diff --git a/src/main/java/net/pterodactylus/sone/data/Sone.java b/src/main/java/net/pterodactylus/sone/data/Sone.java index e124387..ca970c2 100644 --- a/src/main/java/net/pterodactylus/sone/data/Sone.java +++ b/src/main/java/net/pterodactylus/sone/data/Sone.java @@ -84,6 +84,18 @@ public class Sone implements Fingerprintable, Comparable { } }; + /** Comparator that sorts Sones by number of images (descending). */ + public static final Comparator IMAGE_COUNT_COMPARATOR = new Comparator() { + + /** + * {@inheritDoc} + */ + @Override + public int compare(Sone leftSone, Sone rightSone) { + return rightSone.getAllImages().size() - leftSone.getAllImages().size(); + } + }; + /** Filter to remove Sones that have not been downloaded. */ public static final Filter EMPTY_SONE_FILTER = new Filter() { @@ -138,7 +150,7 @@ public class Sone implements Fingerprintable, Comparable { private final Set posts = Collections.synchronizedSet(new HashSet()); /** All replies. */ - private final Set replies = Collections.synchronizedSet(new HashSet()); + private final Set replies = Collections.synchronizedSet(new HashSet()); /** The IDs of all liked posts. */ private final Set likedPostIds = Collections.synchronizedSet(new HashSet()); @@ -477,7 +489,7 @@ public class Sone implements Fingerprintable, Comparable { * * @return All replies this Sone made */ - public synchronized Set getReplies() { + public synchronized Set getReplies() { return Collections.unmodifiableSet(replies); } @@ -488,7 +500,7 @@ public class Sone implements Fingerprintable, Comparable { * The new (and only) replies of this Sone * @return This Sone (for method chaining) */ - public synchronized Sone setReplies(Collection replies) { + public synchronized Sone setReplies(Collection replies) { this.replies.clear(); this.replies.addAll(replies); return this; @@ -501,7 +513,7 @@ public class Sone implements Fingerprintable, Comparable { * @param reply * The reply to add */ - public synchronized void addReply(Reply reply) { + public synchronized void addReply(PostReply reply) { if (reply.getSone().equals(this)) { replies.add(reply); } @@ -513,7 +525,7 @@ public class Sone implements Fingerprintable, Comparable { * @param reply * The reply to remove */ - public synchronized void removeReply(Reply reply) { + public synchronized void removeReply(PostReply reply) { if (reply.getSone().equals(this)) { replies.remove(reply); } @@ -645,6 +657,41 @@ public class Sone implements Fingerprintable, Comparable { } /** + * Returns a flattened list of all albums of this Sone. The resulting list + * contains parent albums before child albums so that the resulting list can + * be parsed in a single pass. + * + * @return The flattened albums + */ + public List getAllAlbums() { + List flatAlbums = new ArrayList(); + flatAlbums.addAll(albums); + int lastAlbumIndex = 0; + while (lastAlbumIndex < flatAlbums.size()) { + int previousAlbumCount = flatAlbums.size(); + for (Album album : new ArrayList(flatAlbums.subList(lastAlbumIndex, flatAlbums.size()))) { + flatAlbums.addAll(album.getAlbums()); + } + lastAlbumIndex = previousAlbumCount; + } + return flatAlbums; + } + + /** + * Returns all images of a Sone. Images of a album are inserted into this + * list before images of all child albums. + * + * @return The list of all images + */ + public List getAllImages() { + List allImages = new ArrayList(); + for (Album album : getAllAlbums()) { + allImages.addAll(album.getImages()); + } + return allImages; + } + + /** * Adds an album to this Sone. * * @param album @@ -747,10 +794,10 @@ public class Sone implements Fingerprintable, Comparable { } fingerprint.append(")"); - List replies = new ArrayList(getReplies()); + List replies = new ArrayList(getReplies()); Collections.sort(replies, Reply.TIME_COMPARATOR); fingerprint.append("Replies("); - for (Reply reply : replies) { + for (PostReply reply : replies) { fingerprint.append("Reply(").append(reply.getId()).append(')'); } fingerprint.append(')'); @@ -781,33 +828,6 @@ public class Sone implements Fingerprintable, Comparable { } // - // STATIC METHODS - // - - /** - * Flattens the given top-level albums so that the resulting list contains - * parent albums before child albums and the resulting list can be parsed in - * a single pass. - * - * @param albums - * The albums to flatten - * @return The flattened albums - */ - public static List flattenAlbums(Collection albums) { - List flatAlbums = new ArrayList(); - flatAlbums.addAll(albums); - int lastAlbumIndex = 0; - while (lastAlbumIndex < flatAlbums.size()) { - int previousAlbumCount = flatAlbums.size(); - for (Album album : new ArrayList(flatAlbums.subList(lastAlbumIndex, flatAlbums.size()))) { - flatAlbums.addAll(album.getAlbums()); - } - lastAlbumIndex = previousAlbumCount; - } - return flatAlbums; - } - - // // INTERFACE Comparable // diff --git a/src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java b/src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java index d88872e..ab705d7 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/AbstractSoneCommand.java @@ -22,6 +22,7 @@ import java.util.List; import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.data.Post; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Profile; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; @@ -205,10 +206,10 @@ public abstract class AbstractSoneCommand extends AbstractCommand { * if there is no reply ID stored under the given parameter * name, or if the reply ID is invalid */ - protected Reply getReply(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException { + protected PostReply getReply(SimpleFieldSet simpleFieldSet, String parameterName) throws FcpException { try { String replyId = simpleFieldSet.getString(parameterName); - Reply reply = core.getReply(replyId, false); + PostReply reply = core.getReply(replyId, false); if (reply == null) { throw new FcpException("Could not load reply from “" + replyId + "”."); } @@ -305,7 +306,7 @@ public abstract class AbstractSoneCommand extends AbstractCommand { postBuilder.put(encodeLikes(core.getLikes(post), prefix + "Likes.")); if (includeReplies) { - List replies = core.getReplies(post); + List replies = core.getReplies(post); postBuilder.put(encodeReplies(replies, prefix)); } @@ -334,7 +335,7 @@ public abstract class AbstractSoneCommand extends AbstractCommand { String postPrefix = prefix + postIndex++; postBuilder.put(encodePost(post, postPrefix + ".", includeReplies)); if (includeReplies) { - postBuilder.put(encodeReplies(Filters.filteredList(core.getReplies(post), Reply.FUTURE_REPLIES_FILTER), postPrefix + ".")); + postBuilder.put(encodeReplies(Filters.filteredList(core.getReplies(post), Reply.FUTURE_REPLY_FILTER), postPrefix + ".")); } } @@ -351,12 +352,12 @@ public abstract class AbstractSoneCommand extends AbstractCommand { * {@code null}) * @return The simple field set containing the replies */ - protected SimpleFieldSet encodeReplies(Collection replies, String prefix) { + protected SimpleFieldSet encodeReplies(Collection replies, String prefix) { SimpleFieldSetBuilder replyBuilder = new SimpleFieldSetBuilder(); int replyIndex = 0; replyBuilder.put(prefix + "Replies.Count", replies.size()); - for (Reply reply : replies) { + for (PostReply reply : replies) { String replyPrefix = prefix + "Replies." + replyIndex++ + "."; replyBuilder.put(replyPrefix + "ID", reply.getId()); replyBuilder.put(replyPrefix + "Sone", reply.getSone().getId()); diff --git a/src/main/java/net/pterodactylus/sone/fcp/CreateReplyCommand.java b/src/main/java/net/pterodactylus/sone/fcp/CreateReplyCommand.java index 880d51e..9fc78d6 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/CreateReplyCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/CreateReplyCommand.java @@ -19,6 +19,7 @@ package net.pterodactylus.sone.fcp; import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.data.Post; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.SimpleFieldSetBuilder; @@ -52,7 +53,7 @@ public class CreateReplyCommand extends AbstractSoneCommand { Sone sone = getSone(parameters, "Sone", true); Post post = getPost(parameters, "Post"); String text = getString(parameters, "Text"); - Reply reply = getCore().createReply(sone, post, text); + PostReply reply = getCore().createReply(sone, post, text); return new Response("ReplyCreated", new SimpleFieldSetBuilder().put("Reply", reply.getId()).get()); } diff --git a/src/main/java/net/pterodactylus/sone/fcp/DeleteReplyCommand.java b/src/main/java/net/pterodactylus/sone/fcp/DeleteReplyCommand.java index 4ac9c15..614b23e 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/DeleteReplyCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/DeleteReplyCommand.java @@ -18,16 +18,16 @@ package net.pterodactylus.sone.fcp; import net.pterodactylus.sone.core.Core; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.freenet.SimpleFieldSetBuilder; import net.pterodactylus.sone.freenet.fcp.FcpException; import freenet.support.SimpleFieldSet; import freenet.support.api.Bucket; /** - * FCP command that deletes a {@link Reply}. + * FCP command that deletes a {@link PostReply}. * - * @see Core#deleteReply(Reply) + * @see Core#deleteReply(PostReply) * @author David ‘Bombe’ Roden */ public class DeleteReplyCommand extends AbstractSoneCommand { @@ -47,7 +47,7 @@ public class DeleteReplyCommand extends AbstractSoneCommand { */ @Override public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException { - Reply reply = getReply(parameters, "Reply"); + PostReply reply = getReply(parameters, "Reply"); if (!getCore().isLocalSone(reply.getSone())) { return new ErrorResponse(401, "Not allowed."); } diff --git a/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java b/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java index 2c8f04f..61257e7 100644 --- a/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java +++ b/src/main/java/net/pterodactylus/sone/fcp/LikeReplyCommand.java @@ -18,7 +18,7 @@ package net.pterodactylus.sone.fcp; import net.pterodactylus.sone.core.Core; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.SimpleFieldSetBuilder; import net.pterodactylus.sone.freenet.fcp.FcpException; @@ -47,7 +47,7 @@ public class LikeReplyCommand extends AbstractSoneCommand { */ @Override public Response execute(SimpleFieldSet parameters, Bucket data, AccessType accessType) throws FcpException { - Reply reply = getReply(parameters, "Reply"); + PostReply reply = getReply(parameters, "Reply"); Sone sone = getSone(parameters, "Sone", true); sone.addLikedReplyId(reply.getId()); return new Response("ReplyLiked", new SimpleFieldSetBuilder().put("LikeCount", getCore().getLikes(reply).size()).get()); diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java index de30a5d..019cdb2 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/WebOfTrustConnector.java @@ -74,6 +74,9 @@ public class WebOfTrustConnector implements ConnectorListener { */ public void stop() { pluginConnector.removeConnectorListener(WOT_PLUGIN_NAME, PLUGIN_CONNECTION_IDENTIFIER, this); + synchronized (reply) { + reply.notifyAll(); + } } /** diff --git a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java index 8aa7487..d93317a 100644 --- a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java +++ b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java @@ -83,7 +83,7 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr } /** The version. */ - public static final Version VERSION = new Version(0, 7, 1); + public static final Version VERSION = new Version(0, 7, 2); /** The logger. */ private static final Logger logger = Logging.getLogger(SonePlugin.class); diff --git a/src/main/java/net/pterodactylus/sone/notify/ListNotificationFilters.java b/src/main/java/net/pterodactylus/sone/notify/ListNotificationFilters.java index 3db8912..beeb81e 100644 --- a/src/main/java/net/pterodactylus/sone/notify/ListNotificationFilters.java +++ b/src/main/java/net/pterodactylus/sone/notify/ListNotificationFilters.java @@ -22,6 +22,7 @@ import java.util.Collection; import java.util.List; import net.pterodactylus.sone.data.Post; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.wot.OwnIdentity; @@ -60,7 +61,7 @@ public class ListNotificationFilters { filteredNotifications.add(filteredNotification); } } else if (notification.getId().equals("new-reply-notification")) { - ListNotification filteredNotification = filterNewReplyNotification((ListNotification) notification, currentSone); + ListNotification filteredNotification = filterNewReplyNotification((ListNotification) notification, currentSone); if (filteredNotification != null) { filteredNotifications.add(filteredNotification); } @@ -129,12 +130,12 @@ public class ListNotificationFilters { * @return The filtered new-reply notification, or {@code null} if the * notification should be removed */ - public static ListNotification filterNewReplyNotification(ListNotification newReplyNotification, Sone currentSone) { + public static ListNotification filterNewReplyNotification(ListNotification newReplyNotification, Sone currentSone) { if (currentSone == null) { return null; } - List newReplies = new ArrayList(); - for (Reply reply : newReplyNotification.getElements()) { + List newReplies = new ArrayList(); + for (PostReply reply : newReplyNotification.getElements()) { if (isReplyVisible(currentSone, reply)) { newReplies.add(reply); } @@ -145,7 +146,7 @@ public class ListNotificationFilters { if (newReplies.size() == newReplyNotification.getElements().size()) { return newReplyNotification; } - ListNotification filteredNotification = new ListNotification(newReplyNotification); + ListNotification filteredNotification = new ListNotification(newReplyNotification); filteredNotification.setElements(newReplies); filteredNotification.setLastUpdateTime(newReplyNotification.getLastUpdatedTime()); return filteredNotification; @@ -237,7 +238,7 @@ public class ListNotificationFilters { * @return {@code true} if the reply is considered visible, {@code false} * otherwise */ - public static boolean isReplyVisible(Sone sone, Reply reply) { + public static boolean isReplyVisible(Sone sone, PostReply reply) { Validation.begin().isNotNull("Reply", reply).check(); Post post = reply.getPost(); if (post == null) { diff --git a/src/main/java/net/pterodactylus/sone/template/ImageLinkFilter.java b/src/main/java/net/pterodactylus/sone/template/ImageLinkFilter.java index 9e758cf..063a1de 100644 --- a/src/main/java/net/pterodactylus/sone/template/ImageLinkFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/ImageLinkFilter.java @@ -82,13 +82,8 @@ public class ImageLinkFilter implements Filter { double scale = Math.max(maxWidth / (double) imageWidth, maxHeight / (double) imageHeight); linkTemplateContext.set("width", (int) (imageWidth * scale + 0.5)); linkTemplateContext.set("height", (int) (imageHeight * scale + 0.5)); - if (scale >= 1) { - linkTemplateContext.set("left", String.format("%dpx", (int) ((imageWidth * scale) - maxWidth) / 2)); - linkTemplateContext.set("top", String.format("%dpx", (int) ((imageHeight * scale) - maxHeight) / 2)); - } else { - linkTemplateContext.set("left", String.format("%dpx", (int) (maxWidth - (imageWidth * scale)) / 2)); - linkTemplateContext.set("top", String.format("%dpx", (int) (maxHeight - (imageHeight * scale)) / 2)); - } + linkTemplateContext.set("left", String.format("%dpx", (int) (maxWidth - (imageWidth * scale)) / 2)); + linkTemplateContext.set("top", String.format("%dpx", (int) (maxHeight - (imageHeight * scale)) / 2)); } else { double scale = 1; if ((imageWidth > maxWidth) || (imageHeight > maxHeight)) { diff --git a/src/main/java/net/pterodactylus/sone/template/ParserFilter.java b/src/main/java/net/pterodactylus/sone/template/ParserFilter.java index 3494c21..b53e969 100644 --- a/src/main/java/net/pterodactylus/sone/template/ParserFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/ParserFilter.java @@ -36,6 +36,7 @@ import net.pterodactylus.sone.text.SonePart; import net.pterodactylus.sone.text.SoneTextParser; import net.pterodactylus.sone.text.SoneTextParserContext; import net.pterodactylus.sone.web.page.FreenetRequest; +import net.pterodactylus.util.number.Numbers; import net.pterodactylus.util.template.Filter; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.template.TemplateContext; @@ -87,19 +88,8 @@ public class ParserFilter implements Filter { @Override public Object format(TemplateContext templateContext, Object data, Map parameters) { String text = String.valueOf(data); - int length = -1; - try { - length = Integer.parseInt(parameters.get("length")); - } catch (NumberFormatException nfe1) { - /* ignore. */ - } - if ((length == -1) && (parameters.get("length") != null)) { - try { - length = Integer.parseInt(String.valueOf(templateContext.get(parameters.get("length")))); - } catch (NumberFormatException nfe1) { - /* ignore. */ - } - } + int length = Numbers.safeParseInteger(parameters.get("length"), Numbers.safeParseInteger(templateContext.get(parameters.get("length")), -1)); + int cutOffLength = Numbers.safeParseInteger(parameters.get("cut-off-length"), Numbers.safeParseInteger(templateContext.get(parameters.get("cut-off-length")), length)); String soneKey = parameters.get("sone"); if (soneKey == null) { soneKey = "sone"; @@ -114,27 +104,33 @@ public class ParserFilter implements Filter { try { Iterable parts = soneTextParser.parse(context, new StringReader(text)); if (length > -1) { + int allPartsLength = 0; List shortenedParts = new ArrayList(); for (Part part : parts) { if (part instanceof PlainTextPart) { String longText = ((PlainTextPart) part).getText(); - if (length >= longText.length()) { - shortenedParts.add(part); - } else { - shortenedParts.add(new PlainTextPart(longText.substring(0, length) + "…")); + if (allPartsLength < cutOffLength) { + if ((allPartsLength + longText.length()) > cutOffLength) { + shortenedParts.add(new PlainTextPart(longText.substring(0, cutOffLength - allPartsLength) + "…")); + } else { + shortenedParts.add(part); + } } - length -= longText.length(); + allPartsLength += longText.length(); } else if (part instanceof LinkPart) { - shortenedParts.add(part); - length -= ((LinkPart) part).getText().length(); + if (allPartsLength < cutOffLength) { + shortenedParts.add(part); + } + allPartsLength += ((LinkPart) part).getText().length(); } else { - shortenedParts.add(part); - } - if (length <= 0) { - break; + if (allPartsLength < cutOffLength) { + shortenedParts.add(part); + } } } - parts = shortenedParts; + if (allPartsLength >= length) { + parts = shortenedParts; + } } render(parsedTextWriter, parts); } catch (IOException ioe1) { @@ -233,7 +229,11 @@ public class ParserFilter implements Filter { * The part to render */ private void render(Writer writer, SonePart sonePart) { - renderLink(writer, "viewSone.html?sone=" + sonePart.getSone().getId(), SoneAccessor.getNiceName(sonePart.getSone()), SoneAccessor.getNiceName(sonePart.getSone()), "in-sone"); + if ((sonePart.getSone() != null) && (sonePart.getSone().getName() != null)) { + renderLink(writer, "viewSone.html?sone=" + sonePart.getSone().getId(), SoneAccessor.getNiceName(sonePart.getSone()), SoneAccessor.getNiceName(sonePart.getSone()), "in-sone"); + } else { + renderLink(writer, "/WebOfTrust/ShowIdentity?id=" + sonePart.getSone().getId(), sonePart.getSone().getId(), sonePart.getSone().getId(), "in-sone"); + } } /** diff --git a/src/main/java/net/pterodactylus/sone/template/PostAccessor.java b/src/main/java/net/pterodactylus/sone/template/PostAccessor.java index 99d6845..bef94d6 100644 --- a/src/main/java/net/pterodactylus/sone/template/PostAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/PostAccessor.java @@ -56,7 +56,7 @@ public class PostAccessor extends ReflectionAccessor { public Object get(TemplateContext templateContext, Object object, String member) { Post post = (Post) object; if ("replies".equals(member)) { - return Filters.filteredList(core.getReplies(post), Reply.FUTURE_REPLIES_FILTER); + return Filters.filteredList(core.getReplies(post), Reply.FUTURE_REPLY_FILTER); } else if (member.equals("likes")) { return core.getLikes(post); } else if (member.equals("liked")) { diff --git a/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java b/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java index 1e54d53..24bcfd6 100644 --- a/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/ReplyAccessor.java @@ -18,6 +18,7 @@ package net.pterodactylus.sone.template; import net.pterodactylus.sone.core.Core; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.util.template.Accessor; @@ -50,7 +51,7 @@ public class ReplyAccessor extends ReflectionAccessor { */ @Override public Object get(TemplateContext templateContext, Object object, String member) { - Reply reply = (Reply) object; + PostReply reply = (PostReply) object; if ("likes".equals(member)) { return core.getLikes(reply); } else if (member.equals("liked")) { diff --git a/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java b/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java index 2567284..8bc17a7 100644 --- a/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java @@ -24,7 +24,7 @@ import java.util.Map; import java.util.Set; import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.util.template.Filter; import net.pterodactylus.util.template.TemplateContext; @@ -44,10 +44,10 @@ public class ReplyGroupFilter implements Filter { @Override public Object format(TemplateContext templateContext, Object data, Map parameters) { @SuppressWarnings("unchecked") - List allReplies = (List) data; + List allReplies = (List) data; Map> postSones = new HashMap>(); - Map> postReplies = new HashMap>(); - for (Reply reply : allReplies) { + Map> postReplies = new HashMap>(); + for (PostReply reply : allReplies) { Post post = reply.getPost(); Set sones = postSones.get(post); if (sones == null) { @@ -55,9 +55,9 @@ public class ReplyGroupFilter implements Filter { postSones.put(post, sones); } sones.add(reply.getSone()); - Set replies = postReplies.get(post); + Set replies = postReplies.get(post); if (replies == null) { - replies = new HashSet(); + replies = new HashSet(); postReplies.put(post, replies); } replies.add(reply); diff --git a/src/main/java/net/pterodactylus/sone/text/SoneTextParser.java b/src/main/java/net/pterodactylus/sone/text/SoneTextParser.java index 051c02a..5c12831 100644 --- a/src/main/java/net/pterodactylus/sone/text/SoneTextParser.java +++ b/src/main/java/net/pterodactylus/sone/text/SoneTextParser.java @@ -202,11 +202,14 @@ public class SoneTextParser implements Parser { if (line.length() >= (7 + 43)) { String soneId = line.substring(7, 50); Sone sone = soneProvider.getSone(soneId, false); - if ((sone != null) && (sone.getName() != null)) { - parts.add(new SonePart(sone)); - } else { - parts.add(new PlainTextPart(line.substring(0, 50))); + if (sone == null) { + /* + * don’t use create=true above, we don’t want the + * empty shell. + */ + sone = new Sone(soneId); } + parts.add(new SonePart(sone)); line = line.substring(50); } else { parts.add(new PlainTextPart(line)); diff --git a/src/main/java/net/pterodactylus/sone/web/DeleteReplyPage.java b/src/main/java/net/pterodactylus/sone/web/DeleteReplyPage.java index 226e0d3..4502617 100644 --- a/src/main/java/net/pterodactylus/sone/web/DeleteReplyPage.java +++ b/src/main/java/net/pterodactylus/sone/web/DeleteReplyPage.java @@ -17,7 +17,7 @@ package net.pterodactylus.sone.web; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.web.page.FreenetRequest; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.template.TemplateContext; @@ -53,7 +53,7 @@ public class DeleteReplyPage extends SoneTemplatePage { protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException { super.processTemplate(request, templateContext); String replyId = request.getHttpRequest().getPartAsStringFailsafe("reply", 36); - Reply reply = webInterface.getCore().getReply(replyId); + PostReply reply = webInterface.getCore().getReply(replyId); String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256); if (request.getMethod() == Method.POST) { if (!webInterface.getCore().isLocalSone(reply.getSone())) { diff --git a/src/main/java/net/pterodactylus/sone/web/KnownSonesPage.java b/src/main/java/net/pterodactylus/sone/web/KnownSonesPage.java index e5acad5..0e27265 100644 --- a/src/main/java/net/pterodactylus/sone/web/KnownSonesPage.java +++ b/src/main/java/net/pterodactylus/sone/web/KnownSonesPage.java @@ -97,6 +97,12 @@ public class KnownSonesPage extends SoneTemplatePage { } else { Collections.sort(knownSones, Sone.POST_COUNT_COMPARATOR); } + } else if ("images".equals(sortField)) { + if ("asc".equals(sortOrder)) { + Collections.sort(knownSones, new ReverseComparator(Sone.IMAGE_COUNT_COMPARATOR)); + } else { + Collections.sort(knownSones, Sone.IMAGE_COUNT_COMPARATOR); + } } else { if ("desc".equals(sortOrder)) { Collections.sort(knownSones, new ReverseComparator(Sone.NICE_NAME_COMPARATOR)); diff --git a/src/main/java/net/pterodactylus/sone/web/MarkAsKnownPage.java b/src/main/java/net/pterodactylus/sone/web/MarkAsKnownPage.java index 987fa1f..8cca4d1 100644 --- a/src/main/java/net/pterodactylus/sone/web/MarkAsKnownPage.java +++ b/src/main/java/net/pterodactylus/sone/web/MarkAsKnownPage.java @@ -20,6 +20,7 @@ package net.pterodactylus.sone.web; import java.util.StringTokenizer; import net.pterodactylus.sone.data.Post; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.page.FreenetRequest; @@ -70,7 +71,7 @@ public class MarkAsKnownPage extends SoneTemplatePage { } webInterface.getCore().markPostKnown(post); } else if (type.equals("reply")) { - Reply reply = webInterface.getCore().getReply(id, false); + PostReply reply = webInterface.getCore().getReply(id, false); if (reply == null) { continue; } diff --git a/src/main/java/net/pterodactylus/sone/web/OptionsPage.java b/src/main/java/net/pterodactylus/sone/web/OptionsPage.java index 75e73a0..7b4a634 100644 --- a/src/main/java/net/pterodactylus/sone/web/OptionsPage.java +++ b/src/main/java/net/pterodactylus/sone/web/OptionsPage.java @@ -87,6 +87,12 @@ public class OptionsPage extends SoneTemplatePage { } else { preferences.setCharactersPerPost(charactersPerPost); } + Integer postCutOffLength = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("post-cut-off-length", 10), null); + if (!preferences.validatePostCutOffLength(postCutOffLength)) { + fieldErrors.add("post-cut-off-length"); + } else { + preferences.setPostCutOffLength(postCutOffLength); + } boolean requireFullAccess = request.getHttpRequest().isPartSet("require-full-access"); preferences.setRequireFullAccess(requireFullAccess); Integer positiveTrust = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("positive-trust", 3)); @@ -128,6 +134,7 @@ public class OptionsPage extends SoneTemplatePage { templateContext.set("insertion-delay", preferences.getInsertionDelay()); templateContext.set("posts-per-page", preferences.getPostsPerPage()); templateContext.set("characters-per-post", preferences.getCharactersPerPost()); + templateContext.set("post-cut-off-length", preferences.getPostCutOffLength()); templateContext.set("require-full-access", preferences.isRequireFullAccess()); templateContext.set("positive-trust", preferences.getPositiveTrust()); templateContext.set("negative-trust", preferences.getNegativeTrust()); diff --git a/src/main/java/net/pterodactylus/sone/web/SearchPage.java b/src/main/java/net/pterodactylus/sone/web/SearchPage.java index 91e2a08..832f9d9 100644 --- a/src/main/java/net/pterodactylus/sone/web/SearchPage.java +++ b/src/main/java/net/pterodactylus/sone/web/SearchPage.java @@ -28,6 +28,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import net.pterodactylus.sone.data.Post; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Profile; import net.pterodactylus.sone.data.Profile.Field; import net.pterodactylus.sone.data.Reply; @@ -365,7 +366,7 @@ public class SearchPage extends SoneTemplatePage { if (post.getRecipient() != null) { postString.append(' ').append(SoneStringGenerator.NAME_GENERATOR.generateString(post.getRecipient())); } - for (Reply reply : Filters.filteredList(webInterface.getCore().getReplies(post), Reply.FUTURE_REPLIES_FILTER)) { + for (PostReply reply : Filters.filteredList(webInterface.getCore().getReplies(post), Reply.FUTURE_REPLY_FILTER)) { postString.append(' ').append(SoneStringGenerator.NAME_GENERATOR.generateString(reply.getSone())); postString.append(' ').append(reply.getText()); } diff --git a/src/main/java/net/pterodactylus/sone/web/ViewSonePage.java b/src/main/java/net/pterodactylus/sone/web/ViewSonePage.java index 5d463c0..5fe356d 100644 --- a/src/main/java/net/pterodactylus/sone/web/ViewSonePage.java +++ b/src/main/java/net/pterodactylus/sone/web/ViewSonePage.java @@ -26,7 +26,7 @@ import java.util.Map; import java.util.Set; import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.template.SoneAccessor; import net.pterodactylus.sone.web.page.FreenetRequest; @@ -91,9 +91,9 @@ public class ViewSonePage extends SoneTemplatePage { Pagination postPagination = new Pagination(sonePosts, webInterface.getCore().getPreferences().getPostsPerPage()).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("postPage"), 0)); templateContext.set("postPagination", postPagination); templateContext.set("posts", postPagination.getItems()); - Set replies = sone.getReplies(); - final Map> repliedPosts = new HashMap>(); - for (Reply reply : replies) { + Set replies = sone.getReplies(); + final Map> repliedPosts = new HashMap>(); + for (PostReply reply : replies) { Post post = reply.getPost(); if (repliedPosts.containsKey(post) || sone.equals(post.getSone()) || (sone.equals(post.getRecipient()))) { continue; diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index 7f53419..7320ad5 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -40,6 +40,7 @@ import net.pterodactylus.sone.core.CoreListener; import net.pterodactylus.sone.data.Album; import net.pterodactylus.sone.data.Image; import net.pterodactylus.sone.data.Post; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.L10nFilter; @@ -176,13 +177,13 @@ public class WebInterface implements CoreListener { private final ListNotification newPostNotification; /** The “new reply” notification. */ - private final ListNotification newReplyNotification; + private final ListNotification newReplyNotification; /** The invisible “local post” notification. */ private final ListNotification localPostNotification; /** The invisible “local reply” notification. */ - private final ListNotification localReplyNotification; + private final ListNotification localReplyNotification; /** The “you have been mentioned” notification. */ private final ListNotification mentionNotification; @@ -266,10 +267,10 @@ public class WebInterface implements CoreListener { localPostNotification = new ListNotification("local-post-notification", "posts", localPostNotificationTemplate, false); Template newReplyNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/newReplyNotification.html")); - newReplyNotification = new ListNotification("new-reply-notification", "replies", newReplyNotificationTemplate, false); + newReplyNotification = new ListNotification("new-reply-notification", "replies", newReplyNotificationTemplate, false); Template localReplyNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/newReplyNotification.html")); - localReplyNotification = new ListNotification("local-reply-notification", "replies", localReplyNotificationTemplate, false); + localReplyNotification = new ListNotification("local-reply-notification", "replies", localReplyNotificationTemplate, false); Template mentionNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/mentionNotification.html")); mentionNotification = new ListNotification("mention-notification", "posts", mentionNotificationTemplate, false); @@ -464,8 +465,8 @@ public class WebInterface implements CoreListener { * * @return The new replies */ - public Set getNewReplies() { - return new SetBuilder().addAll(newReplyNotification.getElements()).addAll(localReplyNotification.getElements()).get(); + public Set getNewReplies() { + return new SetBuilder().addAll(newReplyNotification.getElements()).addAll(localReplyNotification.getElements()).get(); } /** @@ -805,7 +806,7 @@ public class WebInterface implements CoreListener { * {@inheritDoc} */ @Override - public void newReplyFound(Reply reply) { + public void newReplyFound(PostReply reply) { boolean isLocal = getCore().isLocalSone(reply.getSone()); if (isLocal) { localReplyNotification.add(reply); @@ -845,7 +846,7 @@ public class WebInterface implements CoreListener { * {@inheritDoc} */ @Override - public void markReplyKnown(Reply reply) { + public void markReplyKnown(PostReply reply) { newReplyNotification.remove(reply); localReplyNotification.remove(reply); mentionNotification.remove(reply.getPost()); @@ -872,7 +873,7 @@ public class WebInterface implements CoreListener { * {@inheritDoc} */ @Override - public void replyRemoved(Reply reply) { + public void replyRemoved(PostReply reply) { newReplyNotification.remove(reply); localReplyNotification.remove(reply); } diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.java index 9f5c882..337a238 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.java @@ -18,7 +18,7 @@ package net.pterodactylus.sone.web.ajax; import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.text.TextFilter; import net.pterodactylus.sone.web.WebInterface; @@ -63,7 +63,7 @@ public class CreateReplyAjaxPage extends JsonPage { return createErrorJsonObject("invalid-post-id"); } text = TextFilter.filter(request.getHttpRequest().getHeader("host"), text); - Reply reply = webInterface.getCore().createReply(sender, post, text); + PostReply reply = webInterface.getCore().createReply(sender, post, text); return createSuccessJsonObject().put("reply", reply.getId()).put("sone", sender.getId()); } diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.java index 7bea4cf..76126f4 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.java @@ -17,7 +17,7 @@ package net.pterodactylus.sone.web.ajax; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; import net.pterodactylus.util.json.JsonObject; @@ -49,7 +49,7 @@ public class DeleteReplyAjaxPage extends JsonPage { @Override protected JsonObject createJsonObject(FreenetRequest request) { String replyId = request.getHttpRequest().getParam("reply"); - Reply reply = webInterface.getCore().getReply(replyId); + PostReply reply = webInterface.getCore().getReply(replyId); if (reply == null) { return createErrorJsonObject("invalid-reply-id"); } 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 539be3d..12a9e8d 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java @@ -23,7 +23,7 @@ import java.util.List; import java.util.Set; import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.template.SoneAccessor; import net.pterodactylus.sone.web.WebInterface; @@ -67,7 +67,7 @@ public class GetLikesAjaxPage extends JsonPage { Set sones = webInterface.getCore().getLikes(post); return createSuccessJsonObject().put("likes", sones.size()).put("sones", getSones(sones)); } else if ("reply".equals(type)) { - Reply reply = webInterface.getCore().getReply(id); + PostReply reply = webInterface.getCore().getReply(id); Set sones = webInterface.getCore().getLikes(reply); return createSuccessJsonObject().put("likes", sones.size()).put("sones", getSones(sones)); } diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetNotificationAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetNotificationAjaxPage.java index dfac8e4..6cdbf12 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetNotificationAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetNotificationAjaxPage.java @@ -21,7 +21,7 @@ import java.io.IOException; import java.io.StringWriter; import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.main.SonePlugin; import net.pterodactylus.sone.notify.ListNotification; @@ -89,7 +89,7 @@ public class GetNotificationAjaxPage extends JsonPage { if ("new-post-notification".equals(notificationId)) { notification = ListNotificationFilters.filterNewPostNotification((ListNotification) notification, currentSone, false); } else if ("new-reply-notification".equals(notificationId)) { - notification = ListNotificationFilters.filterNewReplyNotification((ListNotification) notification, currentSone); + notification = ListNotificationFilters.filterNewReplyNotification((ListNotification) notification, currentSone); } else if ("mention-notification".equals(notificationId)) { notification = ListNotificationFilters.filterNewPostNotification((ListNotification) notification, currentSone, false); } diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.java index 2eef58a..f38e0f2 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.java @@ -19,7 +19,7 @@ package net.pterodactylus.sone.web.ajax; import java.io.StringWriter; -import net.pterodactylus.sone.data.Reply; +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; @@ -62,7 +62,7 @@ public class GetReplyAjaxPage extends JsonPage { @Override protected JsonObject createJsonObject(FreenetRequest request) { String replyId = request.getHttpRequest().getParam("reply"); - Reply reply = webInterface.getCore().getReply(replyId); + PostReply reply = webInterface.getCore().getReply(replyId); if ((reply == null) || (reply.getSone() == null)) { return createErrorJsonObject("invalid-reply-id"); } @@ -92,7 +92,7 @@ public class GetReplyAjaxPage extends JsonPage { * The currently logged in Sone (to store in the template) * @return The JSON representation of the reply */ - private JsonObject createJsonReply(FreenetRequest request, Reply reply, Sone currentSone) { + private JsonObject createJsonReply(FreenetRequest request, PostReply reply, Sone currentSone) { JsonObject jsonReply = new JsonObject(); jsonReply.put("id", reply.getId()); jsonReply.put("postId", reply.getPost().getId()); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java index eaa6506..038cfb8 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java @@ -26,7 +26,7 @@ import java.util.List; import java.util.Set; import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.notify.ListNotificationFilters; import net.pterodactylus.sone.template.SoneAccessor; @@ -117,27 +117,27 @@ public class GetStatusAjaxPage extends JsonPage { jsonPosts.add(jsonPost); } /* load new replies. */ - Set newReplies = webInterface.getNewReplies(); + Set newReplies = webInterface.getNewReplies(); if (currentSone != null) { - newReplies = Filters.filteredSet(newReplies, new Filter() { + newReplies = Filters.filteredSet(newReplies, new Filter() { @Override - public boolean filterObject(Reply reply) { + public boolean filterObject(PostReply reply) { return ListNotificationFilters.isReplyVisible(currentSone, reply); } }); } /* remove replies to unknown posts. */ - newReplies = Filters.filteredSet(newReplies, new Filter() { + newReplies = Filters.filteredSet(newReplies, new Filter() { @Override - public boolean filterObject(Reply reply) { + public boolean filterObject(PostReply reply) { return (reply.getPost() != null) && (reply.getPost().getSone() != null); } }); JsonArray jsonReplies = new JsonArray(); - for (Reply reply : newReplies) { + for (PostReply reply : newReplies) { JsonObject jsonReply = new JsonObject(); jsonReply.put("id", reply.getId()); jsonReply.put("sone", reply.getSone().getId()); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.java index 1711a5b..cec9967 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.java @@ -22,7 +22,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; import net.pterodactylus.util.json.JsonObject; @@ -75,7 +75,7 @@ public class GetTimesAjaxPage extends JsonPage { if (allIds.length() > 0) { String[] ids = allIds.split(","); for (String id : ids) { - Reply reply = webInterface.getCore().getReply(id, false); + PostReply reply = webInterface.getCore().getReply(id, false); if (reply == null) { continue; } diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.java index 42ee8b2..0e9b6b7 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.java @@ -19,6 +19,7 @@ package net.pterodactylus.sone.web.ajax; import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.data.Post; +import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; @@ -62,7 +63,7 @@ public class MarkAsKnownAjaxPage extends JsonPage { } core.markPostKnown(post); } else if (type.equals("reply")) { - Reply reply = core.getReply(id, false); + PostReply reply = core.getReply(id, false); if (reply == null) { continue; } diff --git a/src/main/resources/i18n/sone.en.properties b/src/main/resources/i18n/sone.en.properties index 4da0855..4210930 100644 --- a/src/main/resources/i18n/sone.en.properties +++ b/src/main/resources/i18n/sone.en.properties @@ -43,7 +43,8 @@ Page.Options.Option.EnableSoneInsertNotifications.Description=If enabled, this w Page.Options.Section.RuntimeOptions.Title=Runtime Behaviour Page.Options.Option.InsertionDelay.Description=The number of seconds the Sone inserter waits after a modification of a Sone before it is being inserted. Page.Options.Option.PostsPerPage.Description=The number of posts to display on a page before pagination controls are being shown. -Page.Options.Option.CharactersPerPost.Description=The number of characters to display from a post before cutting it off and showing a link to expand it (-1 to disable). +Page.Options.Option.CharactersPerPost.Description=The number of characters to display from a post before cutting it off and showing a link to expand it (-1 to disable). The actual length of the snippet is determined by the option below. +Page.Options.Option.PostCutOffLength.Description=The number of characters that are displayed if a post is deemed to long (see option above). Page.Options.Option.RequireFullAccess.Description=Whether to deny access to Sone to any host that has not been granted full access. Page.Options.Section.TrustOptions.Title=Trust Settings Page.Options.Option.PositiveTrust.Description=The amount of positive trust you want to assign to other Sones by clicking the checkmark below a post or reply. @@ -86,6 +87,17 @@ Page.Index.PostList.Text.NoPostYet=Nobody has written any posts yet. You should Page.KnownSones.Title=Known Sones - Sone Page.KnownSones.Page.Title=Known Sones Page.KnownSones.Text.NoKnownSones=There are currently no known Sones. +Page.KnownSones.Label.Sort=Sort: +Page.KnownSones.Label.FollowedSones=Followed Sones: +Page.KnownSones.Sort.Field.Name=Name +Page.KnownSones.Sort.Field.LastActivity=Last activity +Page.KnownSones.Sort.Field.Posts=Number of posts +Page.KnownSones.Sort.Field.Images=Number of images +Page.KnownSones.Sort.Order.Ascending=Ascending +Page.KnownSones.Sort.Order.Descending=Descending +Page.KnownSones.FollowedSones.ShowOnly=Show only followed Sones +Page.KnownSones.FollowedSones.Hide=Hide followed Sones +Page.KnownSones.Button.Apply=Apply Page.KnownSones.Button.FollowAllSones=Follow all Sones Page.KnownSones.Button.UnfollowAllSones=Unfollow all Sones @@ -290,6 +302,7 @@ View.Sone.Label.LastUpdate=Last update: View.Sone.Text.UnknownDate=unknown View.Sone.Stats.Posts={0,number} {0,choice,0#posts|1#post|1
-
<% album.title|html>
+
<% album.title|html> (<%= View.Sone.Stats.Images|l10n 0=album.images.size>)
<% album.description|html>
<%if album.sone.local> diff --git a/src/main/resources/templates/include/soneMenu.html b/src/main/resources/templates/include/soneMenu.html index 87114cc..128e389 100644 --- a/src/main/resources/templates/include/soneMenu.html +++ b/src/main/resources/templates/include/soneMenu.html @@ -4,7 +4,7 @@
<%sone.niceName|html> - (<%= View.Sone.Stats.Posts|l10n 0=sone.posts.size>, <%= View.Sone.Stats.Replies|l10n 0=sone.replies.size>) + (<%= View.Sone.Stats.Posts|l10n 0=sone.posts.size>, <%= View.Sone.Stats.Replies|l10n 0=sone.replies.size><%if ! sone.allImages.size|match value=0>, <%= View.Sone.Stats.Images|l10n 0=sone.allImages.size><%/if>)
<%foreach sone.albums album> diff --git a/src/main/resources/templates/include/viewPost.html b/src/main/resources/templates/include/viewPost.html index 931365d..a478bba 100644 --- a/src/main/resources/templates/include/viewPost.html +++ b/src/main/resources/templates/include/viewPost.html @@ -24,7 +24,7 @@ <%/if> <% post.text|html|store key=originalText text=true> <% post.text|parse sone=post.sone|store key=parsedText text=true> - <% post.text|parse sone=post.sone length=core.preferences.charactersPerPost|store key=shortText text=true> + <% post.text|parse sone=post.sone length=core.preferences.charactersPerPost cut-off-length=core.preferences.postCutOffLength|store key=shortText text=true>
<% originalText>
<% parsedText>
<% shortText>
diff --git a/src/main/resources/templates/include/viewReply.html b/src/main/resources/templates/include/viewReply.html index ec62887..f8e3e64 100644 --- a/src/main/resources/templates/include/viewReply.html +++ b/src/main/resources/templates/include/viewReply.html @@ -12,7 +12,7 @@ <% reply.text|html|store key=originalText text=true> <% reply.text|parse sone=reply.sone|store key=parsedText text=true> - <% reply.text|parse sone=reply.sone length=core.preferences.charactersPerPost|store key=shortText text=true> + <% reply.text|parse sone=reply.sone length=core.preferences.charactersPerPost cut-off-length=core.preferences.postCutOffLength|store key=shortText text=true>
<% originalText>
<% parsedText>
<% shortText>
diff --git a/src/main/resources/templates/include/viewSone.html b/src/main/resources/templates/include/viewSone.html index ba5c8e4..59ba792 100644 --- a/src/main/resources/templates/include/viewSone.html +++ b/src/main/resources/templates/include/viewSone.html @@ -8,7 +8,7 @@
<%= View.Sone.Label.LastUpdate|l10n|html> "><%sone.lastUpdatedText|html>
-
(<%= View.Sone.Stats.Posts|l10n 0=sone.posts.size>, <%= View.Sone.Stats.Replies|l10n 0=sone.replies.size>)
+
(<%= View.Sone.Stats.Posts|l10n 0=sone.posts.size>, <%= View.Sone.Stats.Replies|l10n 0=sone.replies.size><%if ! sone.allImages.size|match value=0>, <%= View.Sone.Stats.Images|l10n 0=sone.allImages.size><%/if>)
<% sone.requestUri|substring start=4 length=43|html>
diff --git a/src/main/resources/templates/knownSones.html b/src/main/resources/templates/knownSones.html index 260a321..7b42d53 100644 --- a/src/main/resources/templates/knownSones.html +++ b/src/main/resources/templates/knownSones.html @@ -1,53 +1,54 @@ <%include include/head.html> - +

<%= Page.KnownSones.Page.Title|l10n|html>

- +
- Sort: + <%= Page.KnownSones.Label.Sort|l10n|html>
<%ifnull !currentSone>
- Followed Sones: + <%= Page.KnownSones.Label.FollowedSones|l10n|html>
<%/if>
- +
diff --git a/src/main/resources/templates/options.html b/src/main/resources/templates/options.html index 39d579f..2adf57e 100644 --- a/src/main/resources/templates/options.html +++ b/src/main/resources/templates/options.html @@ -11,6 +11,9 @@ getTranslation("WebInterface.DefaultText.Option.CharactersPerPost", function(postsPerPageText) { registerInputTextareaSwap("#sone #options input[name=characters-per-post]", postsPerPageText, "characters-per-post", true, true); }); + getTranslation("WebInterface.DefaultText.Option.PostCutOffLength", function(postCutOffLengthText) { + registerInputTextareaSwap("#sone #options input[name=post-cut-off-length]", postCutOffLengthText, "post-cut-off-length", true, true); + }); getTranslation("WebInterface.DefaultText.Option.PositiveTrust", function(positiveTrustText) { registerInputTextareaSwap("#sone #options input[name=positive-trust]", positiveTrustText, "positive-trust", true, true); }); @@ -68,6 +71,12 @@ <%/if>

+

<%= Page.Options.Option.PostCutOffLength.Description|l10n|html>

+ <%if =post-cut-off-length|in collection=fieldErrors> +

<%= Page.Options.Warnings.ValueNotChanged|l10n|html>

+ <%/if> +

+

checked="checked"<%/if> /> <%= Page.Options.Option.RequireFullAccess.Description|l10n|html>