Replace Reader with String in Parser interface
[Sone.git] / src / main / java / net / pterodactylus / sone / web / WebInterface.java
index a3f3352..f08ad5d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Sone - WebInterface.java - Copyright © 2010–2013 David Roden
+ * Sone - WebInterface.java - Copyright © 2010–2015 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
@@ -17,6 +17,7 @@
 
 package net.pterodactylus.sone.web;
 
+import static com.google.common.collect.FluentIterable.from;
 import static java.util.logging.Logger.getLogger;
 import static net.pterodactylus.util.template.TemplateParser.parse;
 
@@ -37,6 +38,8 @@ import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.pterodactylus.sone.core.Core;
 import net.pterodactylus.sone.core.event.ImageInsertAbortedEvent;
@@ -72,6 +75,9 @@ import net.pterodactylus.sone.main.Loaders;
 import net.pterodactylus.sone.main.ReparseFilter;
 import net.pterodactylus.sone.main.SonePlugin;
 import net.pterodactylus.sone.notify.ListNotification;
+import net.pterodactylus.sone.notify.ListNotificationFilter;
+import net.pterodactylus.sone.notify.PostVisibilityFilter;
+import net.pterodactylus.sone.notify.ReplyVisibilityFilter;
 import net.pterodactylus.sone.template.AlbumAccessor;
 import net.pterodactylus.sone.template.CollectionAccessor;
 import net.pterodactylus.sone.template.CssClassNameFilter;
@@ -129,7 +135,6 @@ import net.pterodactylus.sone.web.page.PageToadletFactory;
 import net.pterodactylus.util.notify.Notification;
 import net.pterodactylus.util.notify.NotificationManager;
 import net.pterodactylus.util.notify.TemplateNotification;
-import net.pterodactylus.util.template.ClassPathTemplateProvider;
 import net.pterodactylus.util.template.CollectionSortFilter;
 import net.pterodactylus.util.template.ContainsFilter;
 import net.pterodactylus.util.template.DateFilter;
@@ -146,14 +151,8 @@ import net.pterodactylus.util.template.TemplateContextFactory;
 import net.pterodactylus.util.template.TemplateProvider;
 import net.pterodactylus.util.template.XmlFilter;
 import net.pterodactylus.util.web.RedirectPage;
-import net.pterodactylus.util.web.StaticPage;
 import net.pterodactylus.util.web.TemplatePage;
 
-import com.google.common.collect.Collections2;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.eventbus.Subscribe;
-import com.google.inject.Inject;
-
 import freenet.clients.http.SessionManager;
 import freenet.clients.http.SessionManager.Session;
 import freenet.clients.http.ToadletContainer;
@@ -161,6 +160,12 @@ import freenet.clients.http.ToadletContext;
 import freenet.l10n.BaseL10n;
 import freenet.support.api.HTTPRequest;
 
+import com.google.common.base.Optional;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+
 /**
  * Bundles functionality that a web interface of a Freenet plugin needs, e.g.
  * references to l10n helpers.
@@ -196,6 +201,10 @@ public class WebInterface {
        /** The parser filter. */
        private final ParserFilter parserFilter;
 
+       private final ListNotificationFilter listNotificationFilter;
+       private final PostVisibilityFilter postVisibilityFilter;
+       private final ReplyVisibilityFilter replyVisibilityFilter;
+
        /** The “new Sone” notification. */
        private final ListNotification<Sone> newSoneNotification;
 
@@ -245,9 +254,12 @@ public class WebInterface {
         *            The Sone plugin
         */
        @Inject
-       public WebInterface(SonePlugin sonePlugin, Loaders loaders) {
+       public WebInterface(SonePlugin sonePlugin, Loaders loaders, ListNotificationFilter listNotificationFilter, PostVisibilityFilter postVisibilityFilter, ReplyVisibilityFilter replyVisibilityFilter) {
                this.sonePlugin = sonePlugin;
                this.loaders = loaders;
+               this.listNotificationFilter = listNotificationFilter;
+               this.postVisibilityFilter = postVisibilityFilter;
+               this.replyVisibilityFilter = replyVisibilityFilter;
                formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword();
                soneTextParser = new SoneTextParser(getCore(), getCore());
 
@@ -286,7 +298,7 @@ public class WebInterface {
                templateContextFactory.addFilter("mod", new ModFilter());
                templateContextFactory.addFilter("paginate", new PaginationFilter());
                templateContextFactory.addProvider(TemplateProvider.TEMPLATE_CONTEXT_PROVIDER);
-               templateContextFactory.addProvider(new ClassPathTemplateProvider(WebInterface.class, "/templates/"));
+               templateContextFactory.addProvider(loaders.getTemplateProvider());
                templateContextFactory.addTemplateObject("webInterface", this);
                templateContextFactory.addTemplateObject("formPassword", formPassword);
 
@@ -456,6 +468,16 @@ public class WebInterface {
                return notificationManager;
        }
 
+       @Nonnull
+       public Optional<Notification> getNotification(@Nonnull String notificationId) {
+               return Optional.fromNullable(notificationManager.getNotification(notificationId));
+       }
+
+       @Nonnull
+       public Collection<Notification> getNotifications(@Nullable Sone currentSone) {
+               return listNotificationFilter.filterNotifications(notificationManager.getNotifications(), currentSone);
+       }
+
        /**
         * Returns the l10n helper of the node.
         *
@@ -493,6 +515,15 @@ public class WebInterface {
                return ImmutableSet.<Post> builder().addAll(newPostNotification.getElements()).addAll(localPostNotification.getElements()).build();
        }
 
+       @Nonnull
+       public Collection<Post> getNewPosts(@Nullable Sone currentSone) {
+               Set<Post> allNewPosts = ImmutableSet.<Post> builder()
+                               .addAll(newPostNotification.getElements())
+                               .addAll(localPostNotification.getElements())
+                               .build();
+               return from(allNewPosts).filter(postVisibilityFilter.isVisible(currentSone)).toSet();
+       }
+
        /**
         * Returns the replies that have been announced as new in the
         * {@link #newReplyNotification}.
@@ -503,6 +534,15 @@ public class WebInterface {
                return ImmutableSet.<PostReply> builder().addAll(newReplyNotification.getElements()).addAll(localReplyNotification.getElements()).build();
        }
 
+       @Nonnull
+       public Collection<PostReply> getNewReplies(@Nullable Sone currentSone) {
+               Set<PostReply> allNewReplies = ImmutableSet.<PostReply>builder()
+                               .addAll(newReplyNotification.getElements())
+                               .addAll(localReplyNotification.getElements())
+                               .build();
+               return from(allNewReplies).filter(replyVisibilityFilter.isVisible(currentSone)).toSet();
+       }
+
        /**
         * Sets whether the current start of the plugin is the first start. It is
         * considered a first start if the configuration file does not exist.
@@ -640,7 +680,7 @@ public class WebInterface {
 
                PageToadletFactory pageToadletFactory = new PageToadletFactory(sonePlugin.pluginRespirator().getHLSimpleClient(), "/Sone/");
                pageToadlets.add(pageToadletFactory.createPageToadlet(new RedirectPage<FreenetRequest>("", "index.html")));
-               pageToadlets.add(pageToadletFactory.createPageToadlet(new IndexPage(indexTemplate, this), "Index"));
+               pageToadlets.add(pageToadletFactory.createPageToadlet(new IndexPage(indexTemplate, this, postVisibilityFilter), "Index"));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new NewPage(newTemplate, this), "New"));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateSonePage(createSoneTemplate, this), "CreateSone"));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new KnownSonesPage(knownSonesTemplate, this), "KnownSones"));
@@ -685,9 +725,9 @@ public class WebInterface {
                pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("emptyAlbumTitle.html", emptyAlbumTitleTemplate, "Page.EmptyAlbumTitle.Title", this)));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new DismissNotificationPage(emptyTemplate, this)));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new SoneTemplatePage("invalid.html", invalidTemplate, "Page.Invalid.Title", this)));
-               pageToadlets.add(pageToadletFactory.createPageToadlet(new StaticPage<FreenetRequest>("css/", "/static/css/", "text/css")));
-               pageToadlets.add(pageToadletFactory.createPageToadlet(new StaticPage<FreenetRequest>("javascript/", "/static/javascript/", "text/javascript")));
-               pageToadlets.add(pageToadletFactory.createPageToadlet(new StaticPage<FreenetRequest>("images/", "/static/images/", "image/png")));
+               pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.<FreenetRequest>loadStaticPage("css/", "/static/css/", "text/css")));
+               pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.<FreenetRequest>loadStaticPage("javascript/", "/static/javascript/", "text/javascript")));
+               pageToadlets.add(pageToadletFactory.createPageToadlet(loaders.<FreenetRequest>loadStaticPage("images/", "/static/images/", "image/png")));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new TemplatePage<FreenetRequest>("OpenSearch.xml", "application/opensearchdescription+xml", templateContextFactory, openSearchTemplate)));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new GetImagePage(this)));
                pageToadlets.add(pageToadletFactory.createPageToadlet(new GetTranslationPage(this)));
@@ -756,7 +796,7 @@ public class WebInterface {
                /* we need no context to find mentioned Sones. */
                Set<Sone> mentionedSones = new HashSet<Sone>();
                try {
-                       for (Part part : soneTextParser.parse(null, new StringReader(text))) {
+                       for (Part part : soneTextParser.parse(null, text)) {
                                if (part instanceof SonePart) {
                                        mentionedSones.add(((SonePart) part).getSone());
                                }
@@ -886,72 +926,46 @@ public class WebInterface {
                newSoneNotification.remove(markSoneKnownEvent.sone());
        }
 
-       /**
-        * Notifies the web interface that a {@link Post} was marked as known.
-        *
-        * @param markPostKnownEvent
-        *            The event
-        */
        @Subscribe
        public void markPostKnown(MarkPostKnownEvent markPostKnownEvent) {
-               newPostNotification.remove(markPostKnownEvent.post());
-               localPostNotification.remove(markPostKnownEvent.post());
-               if (!localSoneMentionedInNewPostOrReply(markPostKnownEvent.post())) {
-                       mentionNotification.remove(markPostKnownEvent.post());
-               }
+               removePost(markPostKnownEvent.post());
        }
 
-       /**
-        * Notifies the web interface that a {@link PostReply} was marked as known.
-        *
-        * @param markPostReplyKnownEvent
-        *            The event
-        */
        @Subscribe
        public void markReplyKnown(MarkPostReplyKnownEvent markPostReplyKnownEvent) {
-               PostReply postReply = markPostReplyKnownEvent.postReply();
-               newReplyNotification.remove(postReply);
-               localReplyNotification.remove(postReply);
-               if (postReply.getPost().isPresent() && !localSoneMentionedInNewPostOrReply(postReply.getPost().get())) {
-                       mentionNotification.remove(postReply.getPost().get());
-               }
+               removeReply(markPostReplyKnownEvent.postReply());
        }
 
-       /**
-        * Notifies the web interface that a {@link Sone} was removed.
-        *
-        * @param soneRemovedEvent
-        *            The event
-        */
        @Subscribe
        public void soneRemoved(SoneRemovedEvent soneRemovedEvent) {
                newSoneNotification.remove(soneRemovedEvent.sone());
+               for (Post post : soneRemovedEvent.sone().getPosts()) {
+                       removePost(post);
+               }
+               for (PostReply postReply : soneRemovedEvent.sone().getReplies()) {
+                       removeReply(postReply);
+               }
        }
 
-       /**
-        * Notifies the web interface that a {@link Post} was removed.
-        *
-        * @param postRemovedEvent
-        *            The event
-        */
        @Subscribe
        public void postRemoved(PostRemovedEvent postRemovedEvent) {
-               newPostNotification.remove(postRemovedEvent.post());
-               localPostNotification.remove(postRemovedEvent.post());
-               if (!localSoneMentionedInNewPostOrReply(postRemovedEvent.post())) {
-                       mentionNotification.remove(postRemovedEvent.post());
+               removePost(postRemovedEvent.post());
+       }
+
+       private void removePost(Post post) {
+               newPostNotification.remove(post);
+               localPostNotification.remove(post);
+               if (!localSoneMentionedInNewPostOrReply(post)) {
+                       mentionNotification.remove(post);
                }
        }
 
-       /**
-        * Notifies the web interface that a {@link PostReply} was removed.
-        *
-        * @param postReplyRemovedEvent
-        *            The event
-        */
        @Subscribe
        public void replyRemoved(PostReplyRemovedEvent postReplyRemovedEvent) {
-               PostReply reply = postReplyRemovedEvent.postReply();
+               removeReply(postReplyRemovedEvent.postReply());
+       }
+
+       private void removeReply(PostReply reply) {
                newReplyNotification.remove(reply);
                localReplyNotification.remove(reply);
                if (reply.getPost().isPresent() && !localSoneMentionedInNewPostOrReply(reply.getPost().get())) {
@@ -1047,9 +1061,10 @@ public class WebInterface {
         */
        @Subscribe
        public void updateFound(UpdateFoundEvent updateFoundEvent) {
-               newVersionNotification.getTemplateContext().set("latestVersion", updateFoundEvent.version());
-               newVersionNotification.getTemplateContext().set("latestEdition", updateFoundEvent.latestEdition());
-               newVersionNotification.getTemplateContext().set("releaseTime", updateFoundEvent.releaseTime());
+               newVersionNotification.set("latestVersion", updateFoundEvent.version());
+               newVersionNotification.set("latestEdition", updateFoundEvent.latestEdition());
+               newVersionNotification.set("releaseTime", updateFoundEvent.releaseTime());
+               newVersionNotification.set("disruptive", updateFoundEvent.disruptive());
                notificationManager.addNotification(newVersionNotification);
        }