From: David ‘Bombe’ Roden Date: Sat, 18 Dec 2010 01:17:50 +0000 (+0100) Subject: Merge branch 'release-0.3.5' X-Git-Tag: 0.3.5^0 X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=commitdiff_plain;h=3e162bec2d62278d32a61aff28fa12de236bb753;hp=7bca4bf87205105867893d822f75ab1e00c885b5 Merge branch 'release-0.3.5' --- diff --git a/pom.xml b/pom.xml index 4024519..8190ea0 100644 --- a/pom.xml +++ b/pom.xml @@ -2,12 +2,12 @@ 4.0.0 net.pterodactylus sone - 0.3.4 + 0.3.5 net.pterodactylus utils - 0.7.2 + 0.7.4 junit diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index c99b055..2ef2d57 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -710,7 +710,9 @@ public class Core implements IdentityListener { */ public void lockSone(Sone sone) { synchronized (lockedSones) { - lockedSones.add(sone); + if (lockedSones.add(sone)) { + coreListenerManager.fireSoneLocked(sone); + } } } @@ -723,7 +725,9 @@ public class Core implements IdentityListener { */ public void unlockSone(Sone sone) { synchronized (lockedSones) { - lockedSones.remove(sone); + if (lockedSones.remove(sone)) { + coreListenerManager.fireSoneUnlocked(sone); + } } } @@ -1117,7 +1121,7 @@ public class Core implements IdentityListener { * @param sone * The Sone to save */ - public void saveSone(Sone sone) { + public synchronized void saveSone(Sone sone) { if (!isLocalSone(sone)) { logger.log(Level.FINE, "Tried to save non-local Sone: %s", sone); return; @@ -1187,6 +1191,7 @@ public class Core implements IdentityListener { } configuration.getStringValue(sonePrefix + "/Friends/" + friendCounter + "/ID").setValue(null); + configuration.save(); logger.log(Level.INFO, "Sone %s saved.", sone); } catch (ConfigurationException ce1) { logger.log(Level.WARNING, "Could not save Sone: " + sone, ce1); @@ -1408,7 +1413,7 @@ public class Core implements IdentityListener { /** * Saves the current options. */ - public void saveConfiguration() { + public synchronized void saveConfiguration() { /* store the options first. */ try { configuration.getIntValue("Option/InsertionDelay").setValue(options.getIntegerOption("InsertionDelay").getReal()); diff --git a/src/main/java/net/pterodactylus/sone/core/CoreListener.java b/src/main/java/net/pterodactylus/sone/core/CoreListener.java index 950e890..5d5e715 100644 --- a/src/main/java/net/pterodactylus/sone/core/CoreListener.java +++ b/src/main/java/net/pterodactylus/sone/core/CoreListener.java @@ -111,4 +111,20 @@ public interface CoreListener extends EventListener { */ public void replyRemoved(Reply reply); + /** + * Notifies a listener when a Sone was locked. + * + * @param sone + * The Sone that was locked + */ + public void soneLocked(Sone sone); + + /** + * Notifies a listener that a Sone was unlocked. + * + * @param sone + * The Sone that was unlocked + */ + public void soneUnlocked(Sone sone); + } diff --git a/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java b/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java index 7ba226b..464342c 100644 --- a/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java +++ b/src/main/java/net/pterodactylus/sone/core/CoreListenerManager.java @@ -171,4 +171,30 @@ public class CoreListenerManager extends AbstractListenerManager(sone.getPosts())); soneProperties.put("replies", new HashSet(sone.getReplies())); soneProperties.put("likedPostIds", new HashSet(sone.getLikedPostIds())); - soneProperties.put("likeReplyIds", new HashSet(sone.getLikedReplyIds())); + soneProperties.put("likedReplyIds", new HashSet(sone.getLikedReplyIds())); } // diff --git a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java index ae7c9d2..5199af6 100644 --- a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java +++ b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java @@ -44,7 +44,6 @@ import freenet.pluginmanager.FredPluginL10n; import freenet.pluginmanager.FredPluginThreadless; import freenet.pluginmanager.FredPluginVersioned; import freenet.pluginmanager.PluginRespirator; -import freenet.pluginmanager.PluginStore; /** * This class interfaces with Freenet. It is the class that is loaded by the @@ -96,9 +95,6 @@ public class SonePlugin implements FredPlugin, FredPluginL10n, FredPluginBaseL10 /** The l10n helper. */ private PluginL10n l10n; - /** The plugin store. */ - private PluginStore pluginStore; - /** The identity manager. */ private IdentityManager identityManager; @@ -228,14 +224,8 @@ public class SonePlugin implements FredPlugin, FredPluginL10n, FredPluginBaseL10 /* stop the identity manager. */ identityManager.stop(); - - /* TODO wait for core to stop? */ - try { - pluginRespirator.putStore(pluginStore); - } catch (DatabaseDisabledException dde1) { - logger.log(Level.WARNING, "Could not store plugin store, database is disabled.", dde1); - } - + } catch (Throwable t1) { + logger.log(Level.SEVERE, "Error while shutting down!", t1); } finally { /* shutdown logger. */ Logging.shutdown(); diff --git a/src/main/java/net/pterodactylus/sone/web/SoneTemplatePage.java b/src/main/java/net/pterodactylus/sone/web/SoneTemplatePage.java index 9a8bd9b..ccd0d05 100644 --- a/src/main/java/net/pterodactylus/sone/web/SoneTemplatePage.java +++ b/src/main/java/net/pterodactylus/sone/web/SoneTemplatePage.java @@ -124,6 +124,21 @@ public class SoneTemplatePage extends TemplatePage { } /** + * Returns the currently logged in Sone. + * + * @param toadletContext + * The toadlet context + * @param create + * {@code true} to create a new session if no session exists, + * {@code false} to not create a new session + * @return The currently logged in Sone, or {@code null} if no Sone is + * currently logged in + */ + protected Sone getCurrentSone(ToadletContext toadletContext, boolean create) { + return webInterface.getCurrentSone(toadletContext, create); + } + + /** * Sets the currently logged in Sone. * * @param toadletContext @@ -192,7 +207,7 @@ public class SoneTemplatePage extends TemplatePage { @Override public boolean isEnabled(ToadletContext toadletContext) { if (requiresLogin()) { - return getCurrentSone(toadletContext) != null; + return getCurrentSone(toadletContext, false) != null; } return true; } diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index 95978ce..d3ec1ee 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -23,8 +23,11 @@ import java.io.Reader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.logging.Level; @@ -132,6 +135,12 @@ public class WebInterface implements CoreListener { /** The “Sone rescued” notification. */ private final ListNotification sonesRescuedNotification; + /** Sone locked notification ticker objects. */ + private final Map lockedSonesTickerObjects = Collections.synchronizedMap(new HashMap()); + + /** The “Sone locked” notification. */ + private final ListNotification lockedSonesNotification; + /** * Creates a new web interface. * @@ -177,6 +186,9 @@ public class WebInterface implements CoreListener { Template sonesRescuedTemplate = templateFactory.createTemplate(createReader("/templates/notify/sonesRescuedNotification.html")); sonesRescuedNotification = new ListNotification("sones-rescued-notification", "sones", sonesRescuedTemplate); + + Template lockedSonesTemplate = templateFactory.createTemplate(createReader("/templates/notify/lockedSonesNotification.html")); + lockedSonesNotification = new ListNotification("sones-locked-notification", "sones", lockedSonesTemplate); } // @@ -234,7 +246,22 @@ public class WebInterface implements CoreListener { * currently logged in */ public Sone getCurrentSone(ToadletContext toadletContext) { - return getCurrentSone(getCurrentSession(toadletContext)); + return getCurrentSone(toadletContext, true); + } + + /** + * Returns the currently logged in Sone. + * + * @param toadletContext + * The toadlet context + * @param create + * {@code true} to create a new session if no session exists, + * {@code false} to not create a new session + * @return The currently logged in Sone, or {@code null} if no Sone is + * currently logged in + */ + public Sone getCurrentSone(ToadletContext toadletContext, boolean create) { + return getCurrentSone(getCurrentSession(toadletContext, create)); } /** @@ -585,6 +612,8 @@ public class WebInterface implements CoreListener { newPostNotification.add(post); if (!hasFirstStartNotification()) { notificationManager.addNotification(newPostNotification); + } else { + getCore().markPostKnown(post); } } @@ -599,6 +628,8 @@ public class WebInterface implements CoreListener { newReplyNotification.add(reply); if (!hasFirstStartNotification()) { notificationManager.addNotification(newReplyNotification); + } else { + getCore().markReplyKnown(reply); } } @@ -631,7 +662,7 @@ public class WebInterface implements CoreListener { */ @Override public void postRemoved(Post post) { - /* TODO */ + newPostNotification.remove(post); } /** @@ -639,7 +670,34 @@ public class WebInterface implements CoreListener { */ @Override public void replyRemoved(Reply reply) { - /* TODO */ + newReplyNotification.remove(reply); + } + + /** + * {@inheritDoc} + */ + @Override + public void soneLocked(final Sone sone) { + Object tickerObject = Ticker.getInstance().registerEvent(System.currentTimeMillis() + (5 * 60) * 1000, new Runnable() { + + @Override + @SuppressWarnings("synthetic-access") + public void run() { + lockedSonesNotification.add(sone); + lockedSonesTickerObjects.remove(sone); + notificationManager.addNotification(lockedSonesNotification); + } + }, "Sone Locked Notification"); + lockedSonesTickerObjects.put(sone, tickerObject); + } + + /** + * {@inheritDoc} + */ + @Override + public void soneUnlocked(Sone sone) { + lockedSonesNotification.remove(sone); + Ticker.getInstance().deregisterEvent(lockedSonesTickerObjects.remove(sone)); } /** diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.java index ec0145a..92d5da6 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.java @@ -20,9 +20,11 @@ package net.pterodactylus.sone.web.ajax; import java.io.StringWriter; import net.pterodactylus.sone.data.Post; +import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.util.io.Closer; import net.pterodactylus.util.json.JsonObject; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.template.TemplateException; @@ -60,8 +62,7 @@ public class GetPostAjaxPage extends JsonPage { if (post == null) { return createErrorJsonObject("invalid-post-id"); } - postTemplate.set("currentSone", getCurrentSone(request.getToadletContext())); - return createSuccessJsonObject().put("post", createJsonPost(post)); + return createSuccessJsonObject().put("post", createJsonPost(post, getCurrentSone(request.getToadletContext()))); } /** @@ -82,24 +83,26 @@ public class GetPostAjaxPage extends JsonPage { * * @param post * The post to create a JSON object from + * @param currentSone + * The currently logged in Sone (to store in the template) * @return The JSON representation of the post */ - private JsonObject createJsonPost(Post post) { + private JsonObject createJsonPost(Post post, Sone currentSone) { JsonObject jsonPost = new JsonObject(); jsonPost.put("id", post.getId()); jsonPost.put("sone", post.getSone().getId()); jsonPost.put("recipient", (post.getRecipient() == null) ? null : post.getRecipient().getId()); jsonPost.put("time", post.getTime()); StringWriter stringWriter = new StringWriter(); - synchronized (postTemplate) { - postTemplate.set("post", post); - try { - postTemplate.render(stringWriter); - } catch (TemplateException te1) { - /* TODO - shouldn’t happen. */ - } finally { - Closer.close(stringWriter); - } + DataProvider dataProvider = postTemplate.createDataProvider(); + dataProvider.setData("post", post); + dataProvider.setData("currentSone", currentSone); + try { + postTemplate.render(dataProvider, stringWriter); + } catch (TemplateException te1) { + /* TODO - shouldn’t happen. */ + } finally { + Closer.close(stringWriter); } jsonPost.put("html", stringWriter.toString()); return jsonPost; 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 0963b09..e589191 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.java @@ -20,9 +20,11 @@ package net.pterodactylus.sone.web.ajax; import java.io.StringWriter; import net.pterodactylus.sone.data.Reply; +import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.util.io.Closer; import net.pterodactylus.util.json.JsonObject; +import net.pterodactylus.util.template.DataProvider; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.template.TemplateException; @@ -63,8 +65,7 @@ public class GetReplyAjaxPage extends JsonPage { if ((reply == null) || (reply.getSone() == null)) { return createErrorJsonObject("invalid-reply-id"); } - replyTemplate.set("currentSone", getCurrentSone(request.getToadletContext())); - return createSuccessJsonObject().put("reply", createJsonReply(reply)); + return createSuccessJsonObject().put("reply", createJsonReply(reply, getCurrentSone(request.getToadletContext()))); } /** @@ -84,24 +85,26 @@ public class GetReplyAjaxPage extends JsonPage { * * @param reply * The reply to convert + * @param currentSone + * The currently logged in Sone (to store in the template) * @return The JSON representation of the reply */ - private JsonObject createJsonReply(Reply reply) { + private JsonObject createJsonReply(Reply reply, Sone currentSone) { JsonObject jsonReply = new JsonObject(); jsonReply.put("id", reply.getId()); jsonReply.put("postId", reply.getPost().getId()); jsonReply.put("soneId", reply.getSone().getId()); jsonReply.put("time", reply.getTime()); StringWriter stringWriter = new StringWriter(); - synchronized (replyTemplate) { - replyTemplate.set("reply", reply); - try { - replyTemplate.render(stringWriter); - } catch (TemplateException te1) { - /* TODO - shouldn’t happen. */ - } finally { - Closer.close(stringWriter); - } + DataProvider dataProvider = replyTemplate.createDataProvider(); + dataProvider.setData("reply", reply); + dataProvider.setData("currentSone", currentSone); + try { + replyTemplate.render(dataProvider, stringWriter); + } catch (TemplateException te1) { + /* TODO - shouldn’t happen. */ + } finally { + Closer.close(stringWriter); } return jsonReply.put("html", stringWriter.toString()); } diff --git a/src/main/resources/i18n/sone.en.properties b/src/main/resources/i18n/sone.en.properties index 89af2d1..e080e4d 100644 --- a/src/main/resources/i18n/sone.en.properties +++ b/src/main/resources/i18n/sone.en.properties @@ -186,4 +186,4 @@ Notification.NewReply.Text=New replies have been discovered by the following Son Notification.SoneIsBeingRescued.Text=The following Sones are currently being rescued: Notification.SoneRescued.Text=The following Sones have been rescued: Notification.SoneRescued.Text.RememberToUnlock=Please remember to control the posts and replies you have given and don’t forget to unlock your Sones! - +Notification.LockedSones.Text=The following Sones have been locked for more than 5 minutes. Please check if you really want to keep these Sones locked: diff --git a/src/main/resources/templates/include/viewPost.html b/src/main/resources/templates/include/viewPost.html index 1d938d1..cd6cc5c 100644 --- a/src/main/resources/templates/include/viewPost.html +++ b/src/main/resources/templates/include/viewPost.html @@ -19,7 +19,7 @@
-
⬆
+
↑
<%ifnull ! currentSone>
<% reply.time|date format="MMM d, yyyy, HH:mm:ss">
-
⬆
+
↑
<%ifnull ! currentSone> diff --git a/src/main/resources/templates/notify/lockedSonesNotification.html b/src/main/resources/templates/notify/lockedSonesNotification.html new file mode 100644 index 0000000..b2b8b95 --- /dev/null +++ b/src/main/resources/templates/notify/lockedSonesNotification.html @@ -0,0 +1,6 @@ +
+ <%= Notification.LockedSones.Text|l10n|html> + <%foreach sones sone> + <% sone.niceName|html><%notlast>,<%/notlast><%last>.<%/last> + <%/foreach> +