X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fnet%2Fpterodactylus%2Fsone%2Fweb%2FWebInterface.java;h=9e5e0ebbdcf3d693c92a6635358286d0aadfa054;hp=5ba3be7ef73754064e5fe1bd73571acc182832ad;hb=de3f83202862d1b12505eff4da668a736a355b72;hpb=ac3b11129679548836a3603f0db756986c83e675 diff --git a/src/main/java/net/pterodactylus/sone/web/WebInterface.java b/src/main/java/net/pterodactylus/sone/web/WebInterface.java index 5ba3be7..9e5e0eb 100644 --- a/src/main/java/net/pterodactylus/sone/web/WebInterface.java +++ b/src/main/java/net/pterodactylus/sone/web/WebInterface.java @@ -1,5 +1,5 @@ /* - * Sone - WebInterface.java - Copyright © 2010 David Roden + * Sone - WebInterface.java - Copyright © 2010–2012 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 @@ -37,10 +37,21 @@ import java.util.logging.Logger; import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.core.CoreListener; +import net.pterodactylus.sone.core.event.MarkPostKnownEvent; +import net.pterodactylus.sone.core.event.MarkPostReplyKnownEvent; +import net.pterodactylus.sone.core.event.MarkSoneKnownEvent; +import net.pterodactylus.sone.core.event.NewPostFoundEvent; +import net.pterodactylus.sone.core.event.NewPostReplyFoundEvent; +import net.pterodactylus.sone.core.event.NewSoneFoundEvent; +import net.pterodactylus.sone.core.event.PostRemovedEvent; +import net.pterodactylus.sone.core.event.PostReplyRemovedEvent; +import net.pterodactylus.sone.core.event.SoneLockedEvent; +import net.pterodactylus.sone.core.event.SoneRemovedEvent; 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.Profile; import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.freenet.L10nFilter; @@ -58,6 +69,7 @@ import net.pterodactylus.sone.template.ImageLinkFilter; import net.pterodactylus.sone.template.JavascriptFilter; import net.pterodactylus.sone.template.ParserFilter; import net.pterodactylus.sone.template.PostAccessor; +import net.pterodactylus.sone.template.ProfileAccessor; import net.pterodactylus.sone.template.ReplyAccessor; import net.pterodactylus.sone.template.ReplyGroupFilter; import net.pterodactylus.sone.template.RequestChangeFilter; @@ -82,7 +94,7 @@ import net.pterodactylus.sone.web.ajax.EditImageAjaxPage; import net.pterodactylus.sone.web.ajax.EditProfileFieldAjaxPage; import net.pterodactylus.sone.web.ajax.FollowSoneAjaxPage; import net.pterodactylus.sone.web.ajax.GetLikesAjaxPage; -import net.pterodactylus.sone.web.ajax.GetNotificationAjaxPage; +import net.pterodactylus.sone.web.ajax.GetNotificationsAjaxPage; import net.pterodactylus.sone.web.ajax.GetPostAjaxPage; import net.pterodactylus.sone.web.ajax.GetReplyAjaxPage; import net.pterodactylus.sone.web.ajax.GetStatusAjaxPage; @@ -101,18 +113,11 @@ import net.pterodactylus.sone.web.ajax.UntrustAjaxPage; import net.pterodactylus.sone.web.page.FreenetRequest; import net.pterodactylus.sone.web.page.PageToadlet; import net.pterodactylus.sone.web.page.PageToadletFactory; -import net.pterodactylus.util.cache.Cache; -import net.pterodactylus.util.cache.CacheException; -import net.pterodactylus.util.cache.CacheItem; -import net.pterodactylus.util.cache.DefaultCacheItem; -import net.pterodactylus.util.cache.MemoryCache; -import net.pterodactylus.util.cache.ValueRetriever; -import net.pterodactylus.util.collection.SetBuilder; -import net.pterodactylus.util.filter.Filters; import net.pterodactylus.util.logging.Logging; 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; @@ -120,25 +125,30 @@ import net.pterodactylus.util.template.FormatFilter; import net.pterodactylus.util.template.HtmlFilter; import net.pterodactylus.util.template.MatchFilter; import net.pterodactylus.util.template.ModFilter; -import net.pterodactylus.util.template.Provider; +import net.pterodactylus.util.template.PaginationFilter; import net.pterodactylus.util.template.ReflectionAccessor; import net.pterodactylus.util.template.ReplaceFilter; import net.pterodactylus.util.template.StoreFilter; import net.pterodactylus.util.template.Template; -import net.pterodactylus.util.template.TemplateContext; import net.pterodactylus.util.template.TemplateContextFactory; -import net.pterodactylus.util.template.TemplateException; import net.pterodactylus.util.template.TemplateParser; +import net.pterodactylus.util.template.TemplateProvider; import net.pterodactylus.util.template.XmlFilter; import net.pterodactylus.util.thread.Ticker; import net.pterodactylus.util.version.Version; 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; import freenet.clients.http.ToadletContext; -import freenet.clients.http.SessionManager.Session; import freenet.l10n.BaseL10n; import freenet.support.api.HTTPRequest; @@ -219,7 +229,7 @@ public class WebInterface implements CoreListener { * @param sonePlugin * The Sone plugin */ - @SuppressWarnings("synthetic-access") + @Inject public WebInterface(SonePlugin sonePlugin) { this.sonePlugin = sonePlugin; formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword(); @@ -236,11 +246,12 @@ public class WebInterface implements CoreListener { templateContextFactory.addAccessor(Identity.class, new IdentityAccessor(getCore())); templateContextFactory.addAccessor(Trust.class, new TrustAccessor()); templateContextFactory.addAccessor(HTTPRequest.class, new HttpRequestAccessor()); + templateContextFactory.addAccessor(Profile.class, new ProfileAccessor(getCore())); templateContextFactory.addFilter("date", new DateFilter()); templateContextFactory.addFilter("html", new HtmlFilter()); templateContextFactory.addFilter("replace", new ReplaceFilter()); templateContextFactory.addFilter("store", new StoreFilter()); - templateContextFactory.addFilter("l10n", new L10nFilter(getL10n())); + templateContextFactory.addFilter("l10n", new L10nFilter(this)); templateContextFactory.addFilter("substring", new SubstringFilter()); templateContextFactory.addFilter("xml", new XmlFilter()); templateContextFactory.addFilter("change", new RequestChangeFilter()); @@ -251,13 +262,14 @@ public class WebInterface implements CoreListener { templateContextFactory.addFilter("unknown", new UnknownDateFilter(getL10n(), "View.Sone.Text.UnknownDate")); templateContextFactory.addFilter("format", new FormatFilter()); templateContextFactory.addFilter("sort", new CollectionSortFilter()); - templateContextFactory.addFilter("image-link", new ImageLinkFilter(templateContextFactory)); + templateContextFactory.addFilter("image-link", new ImageLinkFilter(getCore(), templateContextFactory)); templateContextFactory.addFilter("replyGroup", new ReplyGroupFilter()); templateContextFactory.addFilter("in", new ContainsFilter()); templateContextFactory.addFilter("unique", new UniqueElementFilter()); templateContextFactory.addFilter("mod", new ModFilter()); - templateContextFactory.addProvider(Provider.TEMPLATE_CONTEXT_PROVIDER); - templateContextFactory.addProvider(new ClassPathTemplateProvider()); + templateContextFactory.addFilter("paginate", new PaginationFilter()); + templateContextFactory.addProvider(TemplateProvider.TEMPLATE_CONTEXT_PROVIDER); + templateContextFactory.addProvider(new ClassPathTemplateProvider(WebInterface.class, "/templates/")); templateContextFactory.addTemplateObject("webInterface", this); templateContextFactory.addTemplateObject("formPassword", formPassword); @@ -375,7 +387,7 @@ public class WebInterface implements CoreListener { * currently logged in */ public Sone getCurrentSone(ToadletContext toadletContext, boolean create) { - Set localSones = getCore().getLocalSones(); + Collection localSones = getCore().getLocalSones(); if (localSones.size() == 1) { return localSones.iterator().next(); } @@ -461,7 +473,7 @@ public class WebInterface implements CoreListener { * @return The new posts */ public Set getNewPosts() { - return new SetBuilder().addAll(newPostNotification.getElements()).addAll(localPostNotification.getElements()).get(); + return ImmutableSet. builder().addAll(newPostNotification.getElements()).addAll(localPostNotification.getElements()).build(); } /** @@ -471,7 +483,7 @@ public class WebInterface implements CoreListener { * @return The new replies */ public Set getNewReplies() { - return new SetBuilder().addAll(newReplyNotification.getElements()).addAll(localReplyNotification.getElements()).get(); + return ImmutableSet. builder().addAll(newReplyNotification.getElements()).addAll(localReplyNotification.getElements()).build(); } /** @@ -580,6 +592,7 @@ public class WebInterface implements CoreListener { Template emptyTemplate = TemplateParser.parse(new StringReader("")); Template loginTemplate = TemplateParser.parse(createReader("/templates/login.html")); Template indexTemplate = TemplateParser.parse(createReader("/templates/index.html")); + Template newTemplate = TemplateParser.parse(createReader("/templates/new.html")); Template knownSonesTemplate = TemplateParser.parse(createReader("/templates/knownSones.html")); Template createSoneTemplate = TemplateParser.parse(createReader("/templates/createSone.html")); Template createPostTemplate = TemplateParser.parse(createReader("/templates/createPost.html")); @@ -610,6 +623,7 @@ public class WebInterface implements CoreListener { PageToadletFactory pageToadletFactory = new PageToadletFactory(sonePlugin.pluginRespirator().getHLSimpleClient(), "/Sone/"); pageToadlets.add(pageToadletFactory.createPageToadlet(new RedirectPage("", "index.html"))); pageToadlets.add(pageToadletFactory.createPageToadlet(new IndexPage(indexTemplate, this), "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")); pageToadlets.add(pageToadletFactory.createPageToadlet(new EditProfilePage(editProfileTemplate, this), "EditProfile")); @@ -658,7 +672,7 @@ public class WebInterface implements CoreListener { pageToadlets.add(pageToadletFactory.createPageToadlet(new GetImagePage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new GetTranslationPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new GetStatusAjaxPage(this))); - pageToadlets.add(pageToadletFactory.createPageToadlet(new GetNotificationAjaxPage(this))); + pageToadlets.add(pageToadletFactory.createPageToadlet(new GetNotificationsAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new DismissNotificationAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new CreatePostAjaxPage(this))); pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateReplyAjaxPage(this))); @@ -726,15 +740,15 @@ public class WebInterface implements CoreListener { } /** - * Returns all {@link Core#isLocalSone(Sone) local Sone}s that are - * referenced by {@link SonePart}s in the given text (after parsing it using + * Returns all {@link Sone#isLocal() local Sone}s that are referenced by + * {@link SonePart}s in the given text (after parsing it using * {@link SoneTextParser}). * * @param text * The text to parse * @return All mentioned local Sones */ - private Set getMentionedSones(String text) { + private Collection getMentionedSones(String text) { /* we need no context to find mentioned Sones. */ Set mentionedSones = new HashSet(); try { @@ -744,9 +758,9 @@ public class WebInterface implements CoreListener { } } } catch (IOException ioe1) { - logger.log(Level.WARNING, "Could not parse post text: " + text, ioe1); + logger.log(Level.WARNING, String.format("Could not parse post text: %s", text), ioe1); } - return Filters.filteredSet(mentionedSones, Sone.LOCAL_SONE_FILTER); + return Collections2.filter(mentionedSones, Sone.LOCAL_SONE_FILTER); } /** @@ -771,26 +785,33 @@ public class WebInterface implements CoreListener { } // - // CORELISTENER METHODS + // EVENT HANDLERS // /** - * {@inheritDoc} + * Notifies the web interface that a new {@link Sone} was found. + * + * @param newSoneFoundEvent + * The event */ - @Override - public void newSoneFound(Sone sone) { - newSoneNotification.add(sone); + @Subscribe + public void newSoneFound(NewSoneFoundEvent newSoneFoundEvent) { + newSoneNotification.add(newSoneFoundEvent.sone()); if (!hasFirstStartNotification()) { notificationManager.addNotification(newSoneNotification); } } /** - * {@inheritDoc} + * Notifies the web interface that a new {@link Post} was found. + * + * @param newPostFoundEvent + * The event */ - @Override - public void newPostFound(Post post) { - boolean isLocal = getCore().isLocalSone(post.getSone()); + @Subscribe + public void newPostFound(NewPostFoundEvent newPostFoundEvent) { + Post post = newPostFoundEvent.post(); + boolean isLocal = post.getSone().isLocal(); if (isLocal) { localPostNotification.add(post); } else { @@ -808,11 +829,15 @@ public class WebInterface implements CoreListener { } /** - * {@inheritDoc} + * Notifies the web interface that a new {@link PostReply} was found. + * + * @param newPostReplyFoundEvent + * The event */ - @Override - public void newReplyFound(PostReply reply) { - boolean isLocal = getCore().isLocalSone(reply.getSone()); + @Subscribe + public void newReplyFound(NewPostReplyFoundEvent newPostReplyFoundEvent) { + PostReply reply = newPostReplyFoundEvent.postReply(); + boolean isLocal = reply.getSone().isLocal(); if (isLocal) { localReplyNotification.add(reply); } else { @@ -830,64 +855,97 @@ public class WebInterface implements CoreListener { } /** - * {@inheritDoc} + * Notifies the web interface that a {@link Sone} was marked as known. + * + * @param markSoneKnownEvent + * The event */ - @Override - public void markSoneKnown(Sone sone) { - newSoneNotification.remove(sone); + @Subscribe + public void markSoneKnown(MarkSoneKnownEvent markSoneKnownEvent) { + newSoneNotification.remove(markSoneKnownEvent.sone()); } /** - * {@inheritDoc} + * Notifies the web interface that a {@link Post} was marked as known. + * + * @param markPostKnownEvent + * The event */ - @Override - public void markPostKnown(Post post) { - newPostNotification.remove(post); - localPostNotification.remove(post); - mentionNotification.remove(post); + @Subscribe + public void markPostKnown(MarkPostKnownEvent markPostKnownEvent) { + newPostNotification.remove(markPostKnownEvent.post()); + localPostNotification.remove(markPostKnownEvent.post()); + mentionNotification.remove(markPostKnownEvent.post()); } /** - * {@inheritDoc} + * Notifies the web interface that a {@link PostReply} was marked as known. + * + * @param markPostReplyKnownEvent + * The event */ - @Override - public void markReplyKnown(PostReply reply) { - newReplyNotification.remove(reply); - localReplyNotification.remove(reply); - mentionNotification.remove(reply.getPost()); + @Subscribe + public void markReplyKnown(MarkPostReplyKnownEvent markPostReplyKnownEvent) { + newReplyNotification.remove(markPostReplyKnownEvent.postReply()); + localReplyNotification.remove(markPostReplyKnownEvent.postReply()); + mentionNotification.remove(markPostReplyKnownEvent.postReply().getPost()); } /** - * {@inheritDoc} + * Notifies the web interface that a {@link Sone} was removed. + * + * @param soneRemovedEvent + * The event */ - @Override - public void soneRemoved(Sone sone) { - newSoneNotification.remove(sone); + @Subscribe + public void soneRemoved(SoneRemovedEvent soneRemovedEvent) { + newSoneNotification.remove(soneRemovedEvent.sone()); } /** - * {@inheritDoc} + * Notifies the web interface that a {@link Post} was removed. + * + * @param postRemovedEvent + * The event */ - @Override - public void postRemoved(Post post) { - newPostNotification.remove(post); - localPostNotification.remove(post); + @Subscribe + public void postRemoved(PostRemovedEvent postRemovedEvent) { + newPostNotification.remove(postRemovedEvent.post()); + localPostNotification.remove(postRemovedEvent.post()); + mentionNotification.remove(postRemovedEvent.post()); } /** - * {@inheritDoc} + * Notifies the web interface that a {@link PostReply} was removed. + * + * @param postReplyRemovedEvent + * The event */ - @Override - public void replyRemoved(PostReply reply) { + @Subscribe + public void replyRemoved(PostReplyRemovedEvent postReplyRemovedEvent) { + PostReply reply = postReplyRemovedEvent.postReply(); newReplyNotification.remove(reply); localReplyNotification.remove(reply); + if (!getMentionedSones(reply.getText()).isEmpty()) { + boolean isMentioned = false; + for (PostReply existingReply : getCore().getReplies(reply.getPost())) { + isMentioned |= !reply.isKnown() && !getMentionedSones(existingReply.getText()).isEmpty(); + } + if (!isMentioned) { + mentionNotification.remove(reply.getPost()); + } + } } /** - * {@inheritDoc} + * Notifies the web interface that a Sone was locked. + * + * @param soneLockedEvent + * The event */ - @Override - public void soneLocked(final Sone sone) { + @Subscribe + public void soneLocked(SoneLockedEvent soneLockedEvent) { + final Sone sone = soneLockedEvent.sone(); Object tickerObject = Ticker.getInstance().registerEvent(System.currentTimeMillis() + (5 * 60) * 1000, new Runnable() { @Override @@ -901,6 +959,10 @@ public class WebInterface implements CoreListener { lockedSonesTickerObjects.put(sone, tickerObject); } + // + // CORELISTENER METHODS + // + /** * {@inheritDoc} */ @@ -996,66 +1058,4 @@ public class WebInterface implements CoreListener { notificationManager.addNotification(imageInsertFailedNotification); } - /** - * Template provider implementation that uses - * {@link WebInterface#createReader(String)} to load templates for - * inclusion. - * - * @author David ‘Bombe’ Roden - */ - private class ClassPathTemplateProvider implements Provider { - - /** Cache for templates. */ - private final Cache templateCache = new MemoryCache(new ValueRetriever() { - - @Override - @SuppressWarnings("synthetic-access") - public CacheItem