From 7beacff0281aeef1b46b69d4bd61dbbfb4117aa1 Mon Sep 17 00:00:00 2001
From: jrandom <jrandom>
Date: Thu, 8 Dec 2005 00:50:32 +0000
Subject: [PATCH] 2005-12-07  jrandom     * Added a first pass at a blog view
 in Syndie

---
 .../syndie/NewestEntryFirstComparator.java    | 20 ++++
 .../i2p/syndie/NewestNodeFirstComparator.java | 30 ++++++
 .../src/net/i2p/syndie/ThreadNodeImpl.java    |  2 +-
 .../net/i2p/syndie/WritableThreadIndex.java   | 40 --------
 .../i2p/syndie/data/FilteredThreadIndex.java  | 22 +++--
 .../i2p/syndie/sml/ThreadedHTMLRenderer.java  | 31 ++++--
 .../src/net/i2p/syndie/web/BaseServlet.java   | 37 ++++++--
 .../net/i2p/syndie/web/ProfileServlet.java    | 14 ++-
 .../src/net/i2p/syndie/web/RSSServlet.java    |  2 +-
 .../net/i2p/syndie/web/ViewBlogsServlet.java  | 95 +++++++++++++++++++
 .../i2p/syndie/web/ViewThreadedServlet.java   |  4 +-
 apps/syndie/jsp/web.xml                       |  9 ++
 history.txt                                   |  5 +-
 13 files changed, 239 insertions(+), 72 deletions(-)
 create mode 100644 apps/syndie/java/src/net/i2p/syndie/NewestEntryFirstComparator.java
 create mode 100644 apps/syndie/java/src/net/i2p/syndie/NewestNodeFirstComparator.java
 create mode 100644 apps/syndie/java/src/net/i2p/syndie/web/ViewBlogsServlet.java

diff --git a/apps/syndie/java/src/net/i2p/syndie/NewestEntryFirstComparator.java b/apps/syndie/java/src/net/i2p/syndie/NewestEntryFirstComparator.java
new file mode 100644
index 0000000000..21304ef7a4
--- /dev/null
+++ b/apps/syndie/java/src/net/i2p/syndie/NewestEntryFirstComparator.java
@@ -0,0 +1,20 @@
+package net.i2p.syndie;
+
+import java.util.*;
+import net.i2p.data.*;
+import net.i2p.syndie.data.*;
+
+/** sort BlogURI instances with the highest entryId first */
+public class NewestEntryFirstComparator implements Comparator {
+    public int compare(Object lhs, Object rhs) {
+        BlogURI left = (BlogURI)lhs;
+        BlogURI right = (BlogURI)rhs;
+        if (left.getEntryId() > right.getEntryId()) {
+            return -1;
+        } else if (left.getEntryId() == right.getEntryId()) {
+            return DataHelper.compareTo(left.getKeyHash().getData(), right.getKeyHash().getData());
+        } else {
+            return 1;
+        }
+    }
+}
diff --git a/apps/syndie/java/src/net/i2p/syndie/NewestNodeFirstComparator.java b/apps/syndie/java/src/net/i2p/syndie/NewestNodeFirstComparator.java
new file mode 100644
index 0000000000..6046bf0c7f
--- /dev/null
+++ b/apps/syndie/java/src/net/i2p/syndie/NewestNodeFirstComparator.java
@@ -0,0 +1,30 @@
+package net.i2p.syndie;
+
+import java.util.*;
+import net.i2p.data.*;
+
+/** sort ThreadNodeImpl instances with the highest entryId first */
+public class NewestNodeFirstComparator implements Comparator {
+    public int compare(Object lhs, Object rhs) {
+        ThreadNodeImpl left = (ThreadNodeImpl)lhs;
+        ThreadNodeImpl right = (ThreadNodeImpl)rhs;
+        long l = left.getMostRecentPostDate();
+        long r = right.getMostRecentPostDate();
+        if (l > r) { 
+            return -1;
+        } else if (l == r) {
+            // ok, the newest responses match, so lets fall back and compare the roots themselves
+            l = left.getEntry().getEntryId();
+            r = right.getEntry().getEntryId();
+            if (l > r) {
+                return -1;
+            } else if (l == r) {
+                return DataHelper.compareTo(left.getEntry().getKeyHash().getData(), right.getEntry().getKeyHash().getData());
+            } else {
+                return 1;
+            }
+        } else {
+            return 1;
+        }
+    }
+}
diff --git a/apps/syndie/java/src/net/i2p/syndie/ThreadNodeImpl.java b/apps/syndie/java/src/net/i2p/syndie/ThreadNodeImpl.java
index 891d1f5b61..406ca10e4e 100644
--- a/apps/syndie/java/src/net/i2p/syndie/ThreadNodeImpl.java
+++ b/apps/syndie/java/src/net/i2p/syndie/ThreadNodeImpl.java
@@ -80,7 +80,7 @@ class ThreadNodeImpl implements ThreadNode {
         }
         
         // now reorder the children
-        TreeSet ordered = new TreeSet(new WritableThreadIndex.NewestNodeFirstComparator());
+        TreeSet ordered = new TreeSet(new NewestNodeFirstComparator());
         for (int i = 0; i < _children.size(); i++) {
             ThreadNodeImpl kid = (ThreadNodeImpl)_children.get(i);
             ordered.add(kid);
diff --git a/apps/syndie/java/src/net/i2p/syndie/WritableThreadIndex.java b/apps/syndie/java/src/net/i2p/syndie/WritableThreadIndex.java
index 224e03710b..06ffc8e35f 100644
--- a/apps/syndie/java/src/net/i2p/syndie/WritableThreadIndex.java
+++ b/apps/syndie/java/src/net/i2p/syndie/WritableThreadIndex.java
@@ -136,44 +136,4 @@ class WritableThreadIndex extends ThreadIndex {
         buf.append("</threadIndex>\n");
         return buf.toString();
     }
-    
-    /** sort BlogURI instances with the highest entryId first */
-    private class NewestEntryFirstComparator implements Comparator {
-        public int compare(Object lhs, Object rhs) {
-            BlogURI left = (BlogURI)lhs;
-            BlogURI right = (BlogURI)rhs;
-            if (left.getEntryId() > right.getEntryId()) {
-                return -1;
-            } else if (left.getEntryId() == right.getEntryId()) {
-                return DataHelper.compareTo(left.getKeyHash().getData(), right.getKeyHash().getData());
-            } else {
-                return 1;
-            }
-        }
-    }
-    /** sort ThreadNodeImpl instances with the highest entryId first */
-    public static class NewestNodeFirstComparator implements Comparator {
-        public int compare(Object lhs, Object rhs) {
-            ThreadNodeImpl left = (ThreadNodeImpl)lhs;
-            ThreadNodeImpl right = (ThreadNodeImpl)rhs;
-            long l = left.getMostRecentPostDate();
-            long r = right.getMostRecentPostDate();
-            if (l > r) { 
-                return -1;
-            } else if (l == r) {
-                // ok, the newest responses match, so lets fall back and compare the roots themselves
-                l = left.getEntry().getEntryId();
-                r = right.getEntry().getEntryId();
-                if (l > r) {
-                    return -1;
-                } else if (l == r) {
-                    return DataHelper.compareTo(left.getEntry().getKeyHash().getData(), right.getEntry().getKeyHash().getData());
-                } else {
-                    return 1;
-                }
-            } else {
-                return 1;
-            }
-        }
-    }
 }
diff --git a/apps/syndie/java/src/net/i2p/syndie/data/FilteredThreadIndex.java b/apps/syndie/java/src/net/i2p/syndie/data/FilteredThreadIndex.java
index fb9dde9716..eeaa9ee800 100644
--- a/apps/syndie/java/src/net/i2p/syndie/data/FilteredThreadIndex.java
+++ b/apps/syndie/java/src/net/i2p/syndie/data/FilteredThreadIndex.java
@@ -16,11 +16,12 @@ public class FilteredThreadIndex extends ThreadIndex {
     private List _roots;
     private List _ignoredAuthors;
     private Collection _filteredAuthors;
+    private boolean _filterAuthorsByRoot;
 
     public static final String GROUP_FAVORITE = "Favorite";
     public static final String GROUP_IGNORE = "Ignore";
 
-    public FilteredThreadIndex(User user, Archive archive, Collection tags, Collection authors) {
+    public FilteredThreadIndex(User user, Archive archive, Collection tags, Collection authors, boolean filterAuthorsByRoot) {
         super();
         _user = user;
         _archive = archive;
@@ -31,6 +32,7 @@ public class FilteredThreadIndex extends ThreadIndex {
         _filteredAuthors = authors;
         if (_filteredAuthors == null)
             _filteredAuthors = Collections.EMPTY_SET;
+        _filterAuthorsByRoot = filterAuthorsByRoot;
         
         _ignoredAuthors = new ArrayList();
         for (Iterator iter = user.getPetNameDB().iterator(); iter.hasNext(); ) {
@@ -53,12 +55,12 @@ public class FilteredThreadIndex extends ThreadIndex {
         _roots = new ArrayList(_baseIndex.getRootCount());
         for (int i = 0; i < _baseIndex.getRootCount(); i++) {
             ThreadNode node = _baseIndex.getRoot(i);
-            if (!isIgnored(node, _ignoredAuthors, _filteredTags, _filteredAuthors))
+            if (!isIgnored(node, _ignoredAuthors, _filteredTags, _filteredAuthors, _filterAuthorsByRoot))
                 _roots.add(node);
         }
     }
     
-    private boolean isIgnored(ThreadNode node, List ignoredAuthors, Collection requestedTags, Collection filteredAuthors) {
+    private boolean isIgnored(ThreadNode node, List ignoredAuthors, Collection requestedTags, Collection filteredAuthors, boolean filterAuthorsByRoot) {
         if (filteredAuthors.size() <= 0) {
             boolean allAuthorsIgnored = true;
             for (Iterator iter = node.getRecursiveAuthorIterator(); iter.hasNext(); ) {
@@ -75,9 +77,16 @@ public class FilteredThreadIndex extends ThreadIndex {
             boolean filteredAuthorMatches = false;
             for (Iterator iter = filteredAuthors.iterator(); iter.hasNext(); ) {
                 Hash author = (Hash)iter.next();
-                if (node.containsAuthor(author)) {
-                    filteredAuthorMatches = true;
-                    break;
+                if (filterAuthorsByRoot) {
+                    if (node.getEntry().getKeyHash().equals(author)) {
+                        filteredAuthorMatches = true;
+                        break;
+                    }
+                } else { 
+                    if (node.containsAuthor(author)) {
+                        filteredAuthorMatches = true;
+                        break;
+                    }
                 }
             }
             if (!filteredAuthorMatches)
@@ -107,4 +116,5 @@ public class FilteredThreadIndex extends ThreadIndex {
     public ThreadNode getNode(BlogURI uri) { return _baseIndex.getNode(uri); }
     public Collection getFilteredTags() { return _filteredTags; }
     public Collection getFilteredAuthors() { return _filteredAuthors; }
+    public boolean getFilterAuthorsByRoot() { return _filterAuthorsByRoot; }
 }
diff --git a/apps/syndie/java/src/net/i2p/syndie/sml/ThreadedHTMLRenderer.java b/apps/syndie/java/src/net/i2p/syndie/sml/ThreadedHTMLRenderer.java
index ad21c196b0..f981214eaa 100644
--- a/apps/syndie/java/src/net/i2p/syndie/sml/ThreadedHTMLRenderer.java
+++ b/apps/syndie/java/src/net/i2p/syndie/sml/ThreadedHTMLRenderer.java
@@ -41,7 +41,10 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
     /** index into the nav tree to start displaying */
     public static final String PARAM_OFFSET = "offset";
     public static final String PARAM_TAGS = "tags";
+    /** only show threads that the given author participates in */
     public static final String PARAM_AUTHOR = "author";
+    /** only show threads started by the given author */
+    public static final String PARAM_THREAD_AUTHOR = "threadAuthorOnly";
     /** search back through the blog for entries this many days */
     public static final String PARAM_DAYS_BACK = "daysBack";
     // parameters for editing one's profile
@@ -94,7 +97,7 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
         return buf.toString();
     }
     
-    public static String getNavLink(String uri, String viewPost, String viewThread, String tags, String author, int offset) {
+    public static String getNavLink(String uri, String viewPost, String viewThread, String tags, String author, boolean authorOnly, int offset) {
         StringBuffer buf = new StringBuffer(64);
         buf.append(uri);
         buf.append('?');
@@ -106,8 +109,11 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
         if (!empty(tags))
             buf.append(PARAM_TAGS).append('=').append(tags).append('&');
         
-        if (!empty(author))
+        if (!empty(author)) {
             buf.append(PARAM_AUTHOR).append('=').append(author).append('&');
+            if (authorOnly)
+                buf.append(PARAM_THREAD_AUTHOR).append("=true&");
+        }
         
         buf.append(PARAM_OFFSET).append('=').append(offset).append('&');
         
@@ -115,7 +121,7 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
     }
     
     public static String getViewPostLink(String uri, ThreadNode node, User user, boolean isPermalink, 
-                                         String offset, String tags, String author) {
+                                         String offset, String tags, String author, boolean authorOnly) {
         StringBuffer buf = new StringBuffer(64);
         buf.append(uri);
         if (node.getChildCount() > 0) {
@@ -137,15 +143,19 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
                 buf.append(PARAM_OFFSET).append('=').append(offset).append('&');
             if (!empty(tags))
                 buf.append(PARAM_TAGS).append('=').append(tags).append('&');
-            if (!empty(author))
-                buf.append(PARAM_AUTHOR).append('=').append(author).append('&');
         }
         
+        if (authorOnly && !empty(author)) {
+            buf.append(PARAM_AUTHOR).append('=').append(author).append('&');
+            buf.append(PARAM_THREAD_AUTHOR).append("=true&");
+        } else if (!isPermalink && !empty(author))
+            buf.append(PARAM_AUTHOR).append('=').append(author).append('&');
+        
         return buf.toString();
     }
     
     public static String getViewPostLink(String uri, BlogURI post, User user, boolean isPermalink, 
-                                         String offset, String tags, String author) {
+                                         String offset, String tags, String author, boolean authorOnly) {
         StringBuffer buf = new StringBuffer(64);
         buf.append(uri);
         buf.append('?').append(PARAM_VISIBLE).append('=');
@@ -160,8 +170,11 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
                 buf.append(PARAM_OFFSET).append('=').append(offset).append('&');
             if (!empty(tags))
                 buf.append(PARAM_TAGS).append('=').append(tags).append('&');
-            if (!empty(author))
+            if (!empty(author)) {
                 buf.append(PARAM_AUTHOR).append('=').append(author).append('&');
+                if (authorOnly)
+                    buf.append(PARAM_THREAD_AUTHOR).append("=true&");
+            }
         }
         
         return buf.toString();
@@ -174,7 +187,7 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
      */
     public void render(User user, Writer out, Archive archive, BlogURI post, 
                        boolean inlineReply, ThreadIndex index, String baseURI, String replyHiddenFields,
-                       String offset, String requestTags, String filteredAuthor) throws IOException {
+                       String offset, String requestTags, String filteredAuthor, boolean authorOnly) throws IOException {
         EntryContainer entry = archive.getEntry(post);
         if (entry == null) return;
         _entry = entry;
@@ -255,7 +268,7 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
         }
         
         out.write("\n<a href=\"");
-        out.write(getViewPostLink(baseURI, node, user, true, offset, requestTags, filteredAuthor));
+        out.write(getViewPostLink(baseURI, node, user, true, offset, requestTags, filteredAuthor, authorOnly));
         out.write("\" title=\"Select a shareable link directly to this post\">permalink</a>\n");
 
 
diff --git a/apps/syndie/java/src/net/i2p/syndie/web/BaseServlet.java b/apps/syndie/java/src/net/i2p/syndie/web/BaseServlet.java
index 8c5c809914..65e7e078e1 100644
--- a/apps/syndie/java/src/net/i2p/syndie/web/BaseServlet.java
+++ b/apps/syndie/java/src/net/i2p/syndie/web/BaseServlet.java
@@ -152,12 +152,20 @@ public abstract class BaseServlet extends HttpServlet {
         
         FilteredThreadIndex index = (FilteredThreadIndex)req.getSession().getAttribute("threadIndex");
         
+        boolean authorOnly = Boolean.valueOf(req.getParameter(ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR)).booleanValue();
+        if ( (index != null) && (authorOnly != index.getFilterAuthorsByRoot()) )
+            forceNewIndex = true;
+        
         Collection tags = getFilteredTags(req);
         Collection filteredAuthors = getFilteredAuthors(req);
         boolean tagsChanged = ( (index != null) && (!index.getFilteredTags().equals(tags)) );
         boolean authorsChanged = ( (index != null) && (!index.getFilteredAuthors().equals(filteredAuthors)) );
+        
+        if (_log.shouldLog(Log.DEBUG))
+            _log.debug("authorOnly=" + authorOnly + " forceNewIndex? " + forceNewIndex + " authors=" + filteredAuthors);
+        
         if (forceNewIndex || (index == null) || (tagsChanged) || (authorsChanged) ) {
-            index = new FilteredThreadIndex(user, BlogManager.instance().getArchive(), getFilteredTags(req), filteredAuthors);
+            index = new FilteredThreadIndex(user, BlogManager.instance().getArchive(), getFilteredTags(req), filteredAuthors, authorOnly);
             req.getSession().setAttribute("threadIndex", index);
             if (_log.shouldLog(Log.INFO))
                 _log.info("New filtered index created (forced? " + forceNewIndex + ", tagsChanged? " + tagsChanged + ", authorsChanged? " + authorsChanged + ")");
@@ -561,7 +569,7 @@ public abstract class BaseServlet extends HttpServlet {
         //out.write("<tr class=\"topNav\"><td class=\"topNav_user\" colspan=\"2\" nowrap=\"true\">\n");
         out.write("<tr class=\"topNav\"><td colspan=\"3\" nowrap=\"true\"><span class=\"topNav_user\">\n");
         out.write("<!-- nav bar begin -->\n");
-        out.write("<a href=\"threads.jsp\" title=\"Syndie home\">Home</a> ");
+        out.write("<a href=\"threads.jsp\" title=\"Syndie home\">Home</a> <a href=\"blogs.jsp\" title=\"Blog summary\">Blogs</a> ");
         if (user.getAuthenticated() && (user.getBlog() != null) ) {
             out.write("Logged in as <a href=\"" + getProfileLink(req, user.getBlog()) + "\" title=\"Edit your profile\">");
             out.write(user.getUsername());
@@ -933,22 +941,25 @@ public abstract class BaseServlet extends HttpServlet {
         return ThreadedHTMLRenderer.getViewPostLink(req.getRequestURI(), node, user, isPermalink, 
                                                     req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET), 
                                                     req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS), 
-                                                    req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
+                                                    req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR),
+                                                    Boolean.valueOf(req.getParameter(ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR)).booleanValue());
     }
     protected String getViewPostLink(HttpServletRequest req, BlogURI post, User user) {
         return ThreadedHTMLRenderer.getViewPostLink(req.getRequestURI(), post, user, false, 
                                                     req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET), 
                                                     req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS), 
-                                                    req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
+                                                    req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR),
+                                                    Boolean.valueOf(req.getParameter(ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR)).booleanValue());
     }
     protected String getViewThreadLink(HttpServletRequest req, ThreadNode node, User user) {
         return getViewThreadLink(req.getRequestURI(), node, user,
                                  req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET),
                                  req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
-                                 req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
+                                 req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR),
+                                 Boolean.valueOf(req.getParameter(ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR)).booleanValue());
     }
     protected static String getViewThreadLink(String uri, ThreadNode node, User user, String offset,
-                                            String tags, String author) {
+                                            String tags, String author, boolean authorOnly) {
         StringBuffer buf = new StringBuffer(64);
         buf.append(uri);
         BlogURI expandTo = node.getEntry();
@@ -975,8 +986,11 @@ public abstract class BaseServlet extends HttpServlet {
         if (!empty(tags))
             buf.append(ThreadedHTMLRenderer.PARAM_TAGS).append('=').append(tags).append('&');
         
-        if (!empty(author))
+        if (!empty(author)) {
             buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(author).append('&');
+            if (authorOnly)
+                buf.append(ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR).append("=true&");
+        }
         
         buf.append("#").append(node.getEntry().toString());
         return buf.toString();
@@ -990,6 +1004,7 @@ public abstract class BaseServlet extends HttpServlet {
                                                req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_THREAD), 
                                                req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS), 
                                                req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR), 
+                                               Boolean.valueOf(req.getParameter(ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR)).booleanValue(), 
                                                offset);
     }
     
@@ -1014,7 +1029,13 @@ public abstract class BaseServlet extends HttpServlet {
     }
     
     protected Collection getFilteredAuthors(HttpServletRequest req) {
-        String authors = req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR);
+        List rv = new ArrayList();
+        rv.addAll(getAuthors(req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR)));
+        //rv.addAll(getAuthors(req.getParameter(ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR)));
+        return rv;
+    }
+    
+    private Collection getAuthors(String authors) {
         if (authors != null) {
             StringTokenizer tok = new StringTokenizer(authors, "\n\t ");
             ArrayList rv = new ArrayList();
diff --git a/apps/syndie/java/src/net/i2p/syndie/web/ProfileServlet.java b/apps/syndie/java/src/net/i2p/syndie/web/ProfileServlet.java
index 0432298d35..2e82b6fb71 100644
--- a/apps/syndie/java/src/net/i2p/syndie/web/ProfileServlet.java
+++ b/apps/syndie/java/src/net/i2p/syndie/web/ProfileServlet.java
@@ -103,14 +103,13 @@ public class ProfileServlet extends BaseServlet {
     }
     
     private void renderProfile(User user, String baseURI, PrintWriter out, Hash author, Archive archive) throws IOException {
-        out.write("<tr><td colspan=\"3\">Profile for <a href=\"" + getControlTarget() + "?" 
-                  + ThreadedHTMLRenderer.PARAM_AUTHOR + '=' + author.toBase64() 
-                  + "\" title=\"View threads by the profiled author\">");
+        out.write("<tr><td colspan=\"3\">Profile for ");
         PetName pn = user.getPetNameDB().getByLocation(author.toBase64());
+        String name = null;
         BlogInfo info = archive.getBlogInfo(author);
         if (pn != null) {
             out.write(pn.getName());
-            String name = null;
+            name = null;
             if (info != null)
                 name = info.getProperty(BlogInfo.NAME);
             
@@ -119,7 +118,6 @@ public class ProfileServlet extends BaseServlet {
             
             out.write(" (" + name + ")");
         } else {
-            String name = null;
             if (info != null)
                 name = info.getProperty(BlogInfo.NAME);
             
@@ -130,6 +128,12 @@ public class ProfileServlet extends BaseServlet {
         out.write("</a>");
         if (info != null)
             out.write(" [edition " + info.getEdition() + "]");
+        out.write("<br />\n");
+        out.write("<a href=\"" + getControlTarget() + "?" + ThreadedHTMLRenderer.PARAM_AUTHOR 
+                  + '=' + author.toBase64() + "&" + ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR + "=true&\""
+                  + " title=\"View '" + HTMLRenderer.sanitizeTagParam(name) + "'s blog\">View their blog</a> or ");
+        out.write("<a href=\"" + getControlTarget() + "?" + ThreadedHTMLRenderer.PARAM_AUTHOR
+                  + '=' + author.toBase64() + "&\">threads they have participated in</a>\n");
         out.write("</td></tr>\n");
         
         out.write("<tr><td colspan=\"3\"><hr /></td></tr>\n");
diff --git a/apps/syndie/java/src/net/i2p/syndie/web/RSSServlet.java b/apps/syndie/java/src/net/i2p/syndie/web/RSSServlet.java
index d0e1940103..12e9ccf62c 100644
--- a/apps/syndie/java/src/net/i2p/syndie/web/RSSServlet.java
+++ b/apps/syndie/java/src/net/i2p/syndie/web/RSSServlet.java
@@ -60,7 +60,7 @@ public class RSSServlet extends HttpServlet {
         if (count > 100) count = 100;
         
         Archive archive = BlogManager.instance().getArchive();
-        FilteredThreadIndex index = new FilteredThreadIndex(user, archive, tagSet, null);
+        FilteredThreadIndex index = new FilteredThreadIndex(user, archive, tagSet, null, false);
         List entries = new ArrayList();
         // depth first search of the most recent threads
         for (int i = 0; i < count && i < index.getRootCount(); i++) {
diff --git a/apps/syndie/java/src/net/i2p/syndie/web/ViewBlogsServlet.java b/apps/syndie/java/src/net/i2p/syndie/web/ViewBlogsServlet.java
new file mode 100644
index 0000000000..571e54314e
--- /dev/null
+++ b/apps/syndie/java/src/net/i2p/syndie/web/ViewBlogsServlet.java
@@ -0,0 +1,95 @@
+package net.i2p.syndie.web;
+
+import java.io.*;
+import java.util.*;
+
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import net.i2p.I2PAppContext;
+import net.i2p.client.naming.*;
+import net.i2p.data.*;
+import net.i2p.syndie.*;
+import net.i2p.syndie.data.*;
+import net.i2p.syndie.sml.*;
+
+/**
+ * List the blogs known in the archive
+ *
+ */
+public class ViewBlogsServlet extends BaseServlet {
+    private static final int MAX_AUTHORS_AT_ONCE = 100;
+    private static final int MAX_TAGS = 50;
+    
+    protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index, 
+                                        int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
+        TreeSet orderedRoots = new TreeSet(new NewestEntryFirstComparator());
+        // The thread index is ordered by last updated date, as opposed to root posting date,
+        // so lets reorder things
+        int count = index.getRootCount();
+        for (int i = 0; i < count; i++) {
+            ThreadNode node = index.getRoot(i);
+            orderedRoots.add(node.getEntry());
+        }
+        
+        TreeSet tags = new TreeSet();
+        List writtenAuthors = new ArrayList();
+        out.write("<tr><td colspan=\"3\"><b>Blogs:</b></td></tr>\n");
+        out.write("<tr><td colspan=\"3\">");
+        for (Iterator iter = orderedRoots.iterator(); iter.hasNext() && writtenAuthors.size() < MAX_AUTHORS_AT_ONCE; ) {
+            BlogURI uri= (BlogURI)iter.next();
+            String curTags[] = archive.getEntry(uri).getTags();
+            if (curTags != null)
+                for (int i = 0; i < curTags.length && tags.size() < MAX_TAGS; i++)
+                    tags.add(curTags[i]);
+            if (writtenAuthors.contains(uri.getKeyHash())) {
+                // skip
+            } else {
+                BlogInfo info = archive.getBlogInfo(uri);
+                if (info == null)
+                    continue;
+                String name = info.getProperty(BlogInfo.NAME);
+                if ( (name == null) || (name.trim().length() <= 0) )
+                    name = uri.getKeyHash().toBase64().substring(0,8);
+                String desc = info.getProperty(BlogInfo.DESCRIPTION);
+                if ( (desc == null) || (desc.trim().length() <= 0) ) 
+                    desc = name + "'s blog";
+                String age = null;
+                long dayBegin = BlogManager.instance().getDayBegin();
+                long postId = uri.getEntryId();
+                if (postId >= dayBegin) {
+                    age = "today";
+                } else if (postId >= dayBegin - 24*60*60*1000) {
+                    age = "yesterday";
+                } else {
+                    int daysAgo = (int)((dayBegin - postId + 24*60*60*1000-1)/(24*60*60*1000));
+                    age = daysAgo + " days ago";
+                }
+                
+                out.write("<a href=\"" + getControlTarget() + "?" 
+                          + ThreadedHTMLRenderer.PARAM_AUTHOR + '=' + uri.getKeyHash().toBase64()
+                          + "&" + ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR + "=true&"
+                          + "\" title=\"Posts by " + trim(HTMLRenderer.sanitizeTagParam(name), 32)
+                          + ", last post " + age + "\">");
+                out.write(HTMLRenderer.sanitizeString(desc, 32));
+                out.write("</a> \n");
+                writtenAuthors.add(uri.getKeyHash());
+            }
+        }
+        out.write("</td></tr>\n");
+        
+        out.write("<tr><td colspan=\"3\"><b>Topics:</b></td></tr>\n");
+        out.write("<tr><td colspan=\"3\">");
+        for (Iterator iter = tags.iterator(); iter.hasNext(); ) {
+            String tag = (String)iter.next();
+            out.write("<a href=\"" + getFilterByTagLink(req, null, user, tag, null) 
+                      + "\" title=\"View threads flagged with the tag '" + HTMLRenderer.sanitizeTagParam(tag) + "'\">");
+            out.write(HTMLRenderer.sanitizeString(tag, 32));
+            out.write("</a> ");
+        }
+        out.write("</td></tr>\n");
+    }
+    
+    protected String getTitle() { return "Syndie :: View blogs"; }
+}
diff --git a/apps/syndie/java/src/net/i2p/syndie/web/ViewThreadedServlet.java b/apps/syndie/java/src/net/i2p/syndie/web/ViewThreadedServlet.java
index ce6c3c86d9..23b4ea0d2a 100644
--- a/apps/syndie/java/src/net/i2p/syndie/web/ViewThreadedServlet.java
+++ b/apps/syndie/java/src/net/i2p/syndie/web/ViewThreadedServlet.java
@@ -36,13 +36,15 @@ public class ViewThreadedServlet extends BaseServlet {
         String off = req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET);
         String tags = req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS);
         String author = req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR);
+        
+        boolean authorOnly = Boolean.valueOf(req.getParameter(ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR)).booleanValue(); 
 
         for (int i = 0; i < posts.size(); i++) {
             BlogURI post = (BlogURI)posts.get(i);
             boolean inlineReply = (posts.size() == 1);
             //if (true)
             //    inlineReply = true;
-            renderer.render(user, out, archive, post, inlineReply, index, uri, getAuthActionFields(), off, tags, author);
+            renderer.render(user, out, archive, post, inlineReply, index, uri, getAuthActionFields(), off, tags, author, authorOnly);
         }
     }
     
diff --git a/apps/syndie/jsp/web.xml b/apps/syndie/jsp/web.xml
index d4d7ea68e9..6a57e60a38 100644
--- a/apps/syndie/jsp/web.xml
+++ b/apps/syndie/jsp/web.xml
@@ -64,6 +64,11 @@
      <servlet-class>net.i2p.syndie.web.ThreadNavServlet</servlet-class>
     </servlet>
      
+    <servlet>
+     <servlet-name>net.i2p.syndie.web.ViewBlogsServlet</servlet-name>
+     <servlet-class>net.i2p.syndie.web.ViewBlogsServlet</servlet-class>
+    </servlet>
+     
     <servlet>
 	 <servlet-name>net.i2p.syndie.UpdaterServlet</servlet-name>
 	 <servlet-class>net.i2p.syndie.UpdaterServlet</servlet-class>
@@ -126,6 +131,10 @@
       <servlet-name>net.i2p.syndie.web.ThreadNavServlet</servlet-name>
       <url-pattern>/threadnav/*</url-pattern>
     </servlet-mapping>
+    <servlet-mapping> 
+      <servlet-name>net.i2p.syndie.web.ViewBlogsServlet</servlet-name>
+      <url-pattern>/blogs.jsp</url-pattern>
+    </servlet-mapping>
     
     <session-config>
         <session-timeout>
diff --git a/history.txt b/history.txt
index 4225774f77..22ea816add 100644
--- a/history.txt
+++ b/history.txt
@@ -1,4 +1,7 @@
-$Id: history.txt,v 1.348 2005/12/05 01:14:16 jrandom Exp $
+$Id: history.txt,v 1.349 2005/12/07 15:19:43 jrandom Exp $
+
+2005-12-07  jrandom
+    * Added a first pass at a blog view in Syndie
 
 2005-12-07  jrandom
     * Expand the thread we're viewing to its leaf
-- 
GitLab