2005-11-11 jrandom

* Add filtering threads by author to Syndie, populated with authors in the
      user's addressbook
    * When creating the default user, add
      "http://syndiemedia.i2p/archive/archive.txt" to their addressbook,
      configured to automatically pull updates.  (what other archives should
      be included?)
    * Tiny servlet to help dole out the new routerconsole themes, and bundle
      the installer/resources/themes/** into ./docs/themes/** on both install
      and update.
This commit is contained in:
jrandom
2005-11-12 05:03:51 +00:00
committed by zzz
parent 807d2d3509
commit 14134694d7
9 changed files with 284 additions and 89 deletions

View File

@ -0,0 +1,14 @@
<%
String uri = request.getRequestURI();
if (uri.endsWith(".css")) {
response.setContentType("text/css");
} else if (uri.endsWith(".png")) {
response.setContentType("image/png");
} else if (uri.endsWith(".gif")) {
response.setContentType("image/gif");
} else if (uri.endsWith(".jpg")) {
response.setContentType("image/jpeg");
}
net.i2p.util.FileUtil.readFile(uri, "./docs", response.getOutputStream());
%>

View File

@ -5,6 +5,13 @@
<web-app>
<!-- precompiled servlets -->
<!-- yeah, i'm lazy, using a jsp instead of a servlet.. -->
<servlet-mapping>
<servlet-name>net.i2p.router.web.jsp.viewtheme_jsp</servlet-name>
<url-pattern>/themes/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30

View File

@ -447,6 +447,15 @@ public class BlogManager {
pass = DEFAULT_PASS;
return pass;
}
/**
* If we are a single user instance, when we create the default user, give them
* addressbook entries for each of the following, *and* schedule them for syndication
*
*/
private static final String DEFAULT_SINGLE_USER_ARCHIVES[] = new String[] {
"http://syndiemedia.i2p/archive/archive.txt"
};
public User getDefaultUser() {
User user = new User(_context);
@ -479,6 +488,10 @@ public class BlogManager {
String ok = register(user, getDefaultLogin(), getDefaultPass(), "", "default", "Default Syndie blog", "");
if (User.LOGIN_OK.equals(ok)) {
_log.info("Default user created: " + user);
for (int i = 0; i < DEFAULT_SINGLE_USER_ARCHIVES.length; i++)
user.getPetNameDB().add(new PetName("DefaultArchive" + i, "syndie", "syndiearchive", DEFAULT_SINGLE_USER_ARCHIVES[i]));
scheduleSyndication(DEFAULT_SINGLE_USER_ARCHIVES);
saveUser(user);
return;
} else {
user.invalidate();
@ -906,6 +919,20 @@ public class BlogManager {
System.setProperty("syndie.updateArchives", buf.toString());
Updater.wakeup();
}
public void scheduleSyndication(String locations[]) {
String archives[] = getUpdateArchives();
HashSet locs = new HashSet();
for (int i = 0; (archives != null) && (i < archives.length); i++)
locs.add(archives[i]);
for (int i = 0; (locations != null) && (i < locations.length); i++)
locs.add(locations[i]);
StringBuffer buf = new StringBuffer(64);
for (Iterator iter = locs.iterator(); iter.hasNext(); )
buf.append(iter.next().toString().trim()).append(',');
System.setProperty("syndie.updateArchives", buf.toString());
Updater.wakeup();
}
public void unscheduleSyndication(String location) {
String archives[] = getUpdateArchives();
if ( (archives != null) && (archives.length > 0) ) {

View File

@ -15,11 +15,12 @@ public class FilteredThreadIndex extends ThreadIndex {
private Collection _filteredTags;
private List _roots;
private List _ignoredAuthors;
private Collection _filteredAuthors;
public static final String GROUP_FAVORITE = "Favorite";
public static final String GROUP_IGNORE = "Ignore";
public FilteredThreadIndex(User user, Archive archive, Collection tags) {
public FilteredThreadIndex(User user, Archive archive, Collection tags, Collection authors) {
super();
_user = user;
_archive = archive;
@ -27,6 +28,9 @@ public class FilteredThreadIndex extends ThreadIndex {
_filteredTags = tags;
if (_filteredTags == null)
_filteredTags = Collections.EMPTY_SET;
_filteredAuthors = authors;
if (_filteredAuthors == null)
_filteredAuthors = Collections.EMPTY_SET;
_ignoredAuthors = new ArrayList();
for (Iterator iter = user.getPetNameDB().iterator(); iter.hasNext(); ) {
@ -49,27 +53,44 @@ 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))
if (!isIgnored(node, _ignoredAuthors, _filteredTags, _filteredAuthors))
_roots.add(node);
}
}
private boolean isIgnored(ThreadNode node, List ignoredAuthors, Collection requestedTags) {
boolean allAuthorsIgnored = true;
for (Iterator iter = node.getRecursiveAuthorIterator(); iter.hasNext(); ) {
Hash author = (Hash)iter.next();
if (!ignoredAuthors.contains(author)) {
allAuthorsIgnored = false;
break;
private boolean isIgnored(ThreadNode node, List ignoredAuthors, Collection requestedTags, Collection filteredAuthors) {
if (filteredAuthors.size() <= 0) {
boolean allAuthorsIgnored = true;
for (Iterator iter = node.getRecursiveAuthorIterator(); iter.hasNext(); ) {
Hash author = (Hash)iter.next();
if (!ignoredAuthors.contains(author)) {
allAuthorsIgnored = false;
break;
}
}
if ( (allAuthorsIgnored) && (ignoredAuthors.size() > 0) )
return true;
} else {
boolean filteredAuthorMatches = false;
for (Iterator iter = filteredAuthors.iterator(); iter.hasNext(); ) {
Hash author = (Hash)iter.next();
if (node.containsAuthor(author)) {
filteredAuthorMatches = true;
break;
}
}
if (!filteredAuthorMatches)
return true;
}
if ( (allAuthorsIgnored) && (ignoredAuthors.size() > 0) )
return true;
// ok, author checking passed, so only ignore the thread if tags were specified and the
// thread doesn't contain that tag
if (requestedTags.size() > 0) {
Collection nodeTags = node.getRecursiveTags();
for (Iterator iter = requestedTags.iterator(); iter.hasNext(); )
if (node.getRecursiveTags().contains(iter.next()))
if (nodeTags.contains(iter.next()))
return false;
// authors we aren't ignoring have posted in the thread, but the user is filtering
// posts by tags, and this thread doesn't include any of those tags
@ -85,4 +106,5 @@ public class FilteredThreadIndex extends ThreadIndex {
public ThreadNode getRoot(int index) { return (ThreadNode)_roots.get(index); }
public ThreadNode getNode(BlogURI uri) { return _baseIndex.getNode(uri); }
public Collection getFilteredTags() { return _filteredTags; }
public Collection getFilteredAuthors() { return _filteredAuthors; }
}

View File

@ -34,8 +34,9 @@ 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";
public static final String PARAM_AUTHOR = "author";
public static String getFilterByTagLink(String uri, ThreadNode node, User user, String tag) {
public static String getFilterByTagLink(String uri, ThreadNode node, User user, String tag, String author) {
StringBuffer buf = new StringBuffer(64);
buf.append(uri).append('?');
if (node != null) {
@ -44,12 +45,16 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
buf.append(node.getEntry().getEntryId()).append('&');
}
if ( (tag != null) && (tag.trim().length() > 0) )
buf.append(PARAM_TAGS).append('=').append(tag);
if (!empty(tag))
buf.append(PARAM_TAGS).append('=').append(tag).append('&');
if (!empty(author))
buf.append(PARAM_AUTHOR).append('=').append(author).append('&');
return buf.toString();
}
public static String getNavLink(String uri, String viewPost, String viewThread, String tags, int offset) {
public static String getNavLink(String uri, String viewPost, String viewThread, String tags, String author, int offset) {
StringBuffer buf = new StringBuffer(64);
buf.append(uri);
buf.append('?');
@ -61,13 +66,16 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
if (!empty(tags))
buf.append(PARAM_TAGS).append('=').append(tags).append('&');
if (!empty(author))
buf.append(PARAM_AUTHOR).append('=').append(author).append('&');
buf.append(PARAM_OFFSET).append('=').append(offset).append('&');
return buf.toString();
}
public static String getViewPostLink(String uri, ThreadNode node, User user, boolean isPermalink,
String offset, String tags) {
String offset, String tags, String author) {
StringBuffer buf = new StringBuffer(64);
buf.append(uri);
if (node.getChildCount() > 0) {
@ -84,11 +92,14 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
buf.append(node.getEntry().getKeyHash().toBase64()).append('/');
buf.append(node.getEntry().getEntryId()).append('&');
if ( (!isPermalink) && (!empty(offset)) )
buf.append(PARAM_OFFSET).append('=').append(offset).append('&');
if ( (!isPermalink) && (!empty(tags)) )
buf.append(PARAM_TAGS).append('=').append(tags).append('&');
if (!isPermalink) {
if (!empty(offset))
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('&');
}
return buf.toString();
}
@ -98,7 +109,7 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
public void render(User user, Writer out, Archive archive, BlogURI post,
boolean inlineReply, ThreadIndex index, String baseURI,
String offset, String requestTags) throws IOException {
String offset, String requestTags, String filteredAuthor) throws IOException {
EntryContainer entry = archive.getEntry(post);
if (entry == null) return;
_entry = entry;
@ -126,7 +137,7 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
String subject = (String)_headers.get(HTMLRenderer.HEADER_SUBJECT);
if (subject == null)
subject = "";
out.write(" <td colspan=\"3\" class=\"postMetaSubject\">");
out.write(" <td colspan=\"3\" class=\"postMetaSubject\" id=\"bodySubject\">");
out.write(subject);
out.write("</td></tr>\n");
out.write("<tr class=\"postMeta\"><td colspan=\"3\" class=\"postMetaLink\">\n");
@ -158,7 +169,7 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
for (Iterator tagIter = tags.iterator(); tagIter.hasNext(); ) {
String tag = (String)tagIter.next();
out.write("<a href=\"");
out.write(getFilterByTagLink(baseURI, node, user, tag));
out.write(getFilterByTagLink(baseURI, node, user, tag, filteredAuthor));
out.write("\" title=\"Filter threads to only include posts tagged as '");
out.write(tag);
out.write("'\">");
@ -168,7 +179,7 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
}
out.write("\n<a href=\"");
out.write(getViewPostLink(baseURI, node, user, true, offset, requestTags));
out.write(getViewPostLink(baseURI, node, user, true, offset, requestTags, filteredAuthor));
out.write("\" title=\"Select a shareable link directly to this post\">permalink</a>\n");
out.write("</td>\n</tr>\n");

View File

@ -96,8 +96,9 @@ public class ViewThreadedServlet extends HttpServlet {
FilteredThreadIndex index = (FilteredThreadIndex)req.getSession().getAttribute("threadIndex");
Collection tags = getFilteredTags(req);
if (forceNewIndex || (index == null) || (!index.getFilteredTags().equals(tags)) ) {
index = new FilteredThreadIndex(user, BlogManager.instance().getArchive(), getFilteredTags(req));
Collection filteredAuthors = getFilteredAuthors(req);
if (forceNewIndex || (index == null) || (!index.getFilteredTags().equals(tags)) || (!index.getFilteredAuthors().equals(filteredAuthors))) {
index = new FilteredThreadIndex(user, BlogManager.instance().getArchive(), getFilteredTags(req), filteredAuthors);
req.getSession().setAttribute("threadIndex", index);
}
@ -129,6 +130,7 @@ public class ViewThreadedServlet extends HttpServlet {
renderNavBar(user, req, out, index);
renderControlBar(user, req, out, index);
renderBody(user, req, out, index);
renderThreadNav(user, req, out, threadOffset, index);
renderThreadTree(user, req, out, threadOffset, visibleEntry, archive, index);
renderThreadNav(user, req, out, threadOffset, index);
@ -183,12 +185,15 @@ public class ViewThreadedServlet extends HttpServlet {
out.write(req.getRequestURI());
out.write("\" method=\"GET\">\n");
String tags = "";
String author = "";
Enumeration params = req.getParameterNames();
while (params.hasMoreElements()) {
String param = (String)params.nextElement();
String val = req.getParameter(param);
if (ThreadedHTMLRenderer.PARAM_TAGS.equals(param)) {
tags = val;
} else if (ThreadedHTMLRenderer.PARAM_AUTHOR.equals(param)) {
author = val;
} else if (SKIP_TAGS.contains(param)) {
// skip
} else if (param.length() <= 0) {
@ -199,12 +204,30 @@ public class ViewThreadedServlet extends HttpServlet {
}
out.write("<tr class=\"controlBar\"><td colspan=\"2\">\n");
out.write("<!-- control bar begin -->\n");
out.write("Filter: <select name=\"filter\" disabled=\"true\" >\n");
out.write(" <option value=\"all\">All posts in all threads</option>\n");
out.write(" <option value=\"self\">Threads you have posted in</option>\n");
out.write(" <option value=\"favorites\">Threads your friends have posted in</option>\n");
out.write(" </select>\n");
out.write("Tags: <input type=\"text\" name=\"" + ThreadedHTMLRenderer.PARAM_TAGS + "\" size=\"30\" value=\"" + tags + "\" />\n");
out.write("Filter: <select name=\"" + ThreadedHTMLRenderer.PARAM_AUTHOR + "\">\n");
PetNameDB db = user.getPetNameDB();
TreeSet names = new TreeSet(db.getNames());
out.write("<option value=\"\">Any authors</option>\n");
if (author.equals(user.getBlog().toBase64()))
out.write("<option value=\"" + user.getBlog().toBase64() + "\" selected=\"true\">Threads you posted in</option>\n");
else
out.write("<option value=\"" + user.getBlog().toBase64() + "\">Threads you posted in</option>\n");
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
String name = (String) iter.next();
PetName pn = db.getByName(name);
if ("syndieblog".equals(pn.getProtocol())) {
if (author.equals(pn.getLocation()))
out.write("<option value=\"" + pn.getLocation() + "\" selected=\"true\">Threads " + name + " posted in</option>\n");
else
out.write("<option value=\"" + pn.getLocation() + "\">Threads " + name + " posted in</option>\n");
}
}
out.write("</select>\n");
out.write("Tags: <input type=\"text\" name=\"" + ThreadedHTMLRenderer.PARAM_TAGS + "\" size=\"10\" value=\"" + tags + "\" />\n");
out.write("<input type=\"submit\" name=\"action\" value=\"Go\" />\n");
out.write("</td><td class=\"controlBarRight\"><a href=\"#threads\" title=\"Jump to the thread navigation\">Threads</a></td>\n");
out.write("<!-- control bar end -->\n");
@ -215,13 +238,15 @@ public class ViewThreadedServlet extends HttpServlet {
ThreadedHTMLRenderer renderer = new ThreadedHTMLRenderer(I2PAppContext.getGlobalContext());
Archive archive = BlogManager.instance().getArchive();
List posts = getPosts(archive, req, index);
String uri = req.getRequestURI();
String off = req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET);
String tags = req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS);
String author = req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR);
for (int i = 0; i < posts.size(); i++) {
BlogURI post = (BlogURI)posts.get(i);
renderer.render(user, out, archive, post, posts.size() == 1, index, uri, off, tags);
renderer.render(user, out, archive, post, posts.size() == 1, index, uri, off, tags, author);
}
}
@ -261,9 +286,13 @@ public class ViewThreadedServlet extends HttpServlet {
private void renderThreadNav(User user, HttpServletRequest req, PrintWriter out, int threadOffset, ThreadIndex index) throws IOException {
out.write("<tr class=\"threadNav\" id=\"threads\"><td colspan=\"2\" nowrap=\"true\">\n");
out.write("<!-- thread nav begin -->\n");
out.write("<a href=\"");
out.write(getNavLink(req, 0));
out.write("\">&lt;&lt; First Page</a> ");
if (threadOffset == 0) {
out.write("&lt;&lt; First Page ");
} else {
out.write("<a href=\"");
out.write(getNavLink(req, 0));
out.write("\">&lt;&lt; First Page</a> ");
}
if (threadOffset > 0) {
out.write("<a href=\"");
int nxt = threadOffset - 10;
@ -343,6 +372,24 @@ public class ViewThreadedServlet extends HttpServlet {
return Collections.EMPTY_LIST;
}
}
private Collection getFilteredAuthors(HttpServletRequest req) {
String authors = req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR);
if (authors != null) {
StringTokenizer tok = new StringTokenizer(authors, "\n\t ");
ArrayList rv = new ArrayList();
while (tok.hasMoreTokens()) {
try {
Hash h = new Hash();
h.fromBase64(tok.nextToken().trim());
rv.add(h);
} catch (DataFormatException dfe) {}
}
return rv;
} else {
return Collections.EMPTY_LIST;
}
}
private void renderThreadTree(User user, PrintWriter out, ThreadIndex index, Archive archive, HttpServletRequest req,
int threadOffset, int numThreads, BlogURI visibleEntry) {
@ -359,13 +406,19 @@ public class ViewThreadedServlet extends HttpServlet {
numThreads = index.getRootCount() - threadOffset;
TreeRenderState state = new TreeRenderState(new ArrayList());
int written = 0;
for (int curRoot = threadOffset; curRoot < numThreads + threadOffset; curRoot++) {
ThreadNode node = index.getRoot(curRoot);
out.write("<!-- thread begin node=" + node + " curRoot=" + curRoot + " threadOffset=" + threadOffset + " -->\n");
renderThread(user, out, index, archive, req, node, 0, visibleEntry, state);
out.write("<!-- thread end -->\n");
written++;
}
out.write("<!-- threads begin -->\n");
if (written <= 0)
out.write("<tr class=\"threadEven\"><td colspan=\"3\">No matching threads</td></tr>\n");
out.write("<!-- threads end -->\n");
}
/**
@ -418,11 +471,11 @@ public class ViewThreadedServlet extends HttpServlet {
if (allowCollapse) {
out.write("<a href=\"");
out.write(getCollapseLink(req, node));
out.write("\" title=\"collapse thread\"><img border=\"0\" src=\"images/collapse.png\" alt=\"-\" /></a>\n");
out.write("\" title=\"collapse thread\"><img border=\"0\" src=\"images/collapse.png\" alt=\"collapse\" /></a>\n");
} else {
out.write("<a href=\"");
out.write(getExpandLink(req, node));
out.write("\" title=\"expand thread\"><img border=\"0\" src=\"images/expand.png\" alt=\"+\" /></a>\n");
out.write("\" title=\"expand thread\"><img border=\"0\" src=\"images/expand.png\" alt=\"expand\" /></a>\n");
}
} else {
out.write("<img src=\"images/noSubthread.png\" alt=\"\" border=\"0\" />\n");
@ -539,10 +592,11 @@ public class ViewThreadedServlet extends HttpServlet {
return getExpandLink(node, req.getRequestURI(), req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_POST),
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_THREAD),
req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET),
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS));
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
}
private static String getExpandLink(ThreadNode node, String uri, String viewPost, String viewThread,
String offset, String tags) {
String offset, String tags, String author) {
StringBuffer buf = new StringBuffer(64);
buf.append(uri);
buf.append('?');
@ -565,6 +619,9 @@ public class ViewThreadedServlet extends HttpServlet {
if (!empty(tags))
buf.append(ThreadedHTMLRenderer.PARAM_TAGS).append('=').append(tags).append('&');
if (!empty(author))
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(author).append('&');
return buf.toString();
}
private String getCollapseLink(HttpServletRequest req, ThreadNode node) {
@ -572,11 +629,12 @@ public class ViewThreadedServlet extends HttpServlet {
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_POST),
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_THREAD),
req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET),
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS));
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
}
private String getCollapseLink(ThreadNode node, String uri, String viewPost, String viewThread,
String offset, String tags) {
String offset, String tags, String author) {
StringBuffer buf = new StringBuffer(64);
buf.append(uri);
// collapse node == let the node be visible
@ -595,6 +653,9 @@ public class ViewThreadedServlet extends HttpServlet {
if (!empty(tags))
buf.append(ThreadedHTMLRenderer.PARAM_TAGS).append('=').append(tags).append('&');
if (!empty(author))
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(author).append('&');
return buf.toString();
}
private String getProfileLink(HttpServletRequest req, Hash author) {
@ -608,10 +669,11 @@ public class ViewThreadedServlet extends HttpServlet {
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_POST),
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_THREAD),
req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET),
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS));
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
}
private String getAddToGroupLink(User user, Hash author, String group, String uri, String visible,
String viewPost, String viewThread, String offset, String tags) {
String viewPost, String viewThread, String offset, String tags, String filteredAuthor) {
StringBuffer buf = new StringBuffer(64);
buf.append(uri);
buf.append('?');
@ -631,19 +693,25 @@ public class ViewThreadedServlet extends HttpServlet {
if (!empty(tags))
buf.append(ThreadedHTMLRenderer.PARAM_TAGS).append('=').append(tags).append('&');
if (!empty(filteredAuthor))
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(filteredAuthor).append('&');
return buf.toString();
}
private String getViewPostLink(HttpServletRequest req, ThreadNode node, User user, boolean isPermalink) {
return ThreadedHTMLRenderer.getViewPostLink(req.getRequestURI(), node, user, isPermalink,
req.getParameter(ThreadedHTMLRenderer.PARAM_OFFSET),
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS));
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
}
private 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_TAGS),
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR));
}
private static String getViewThreadLink(String uri, ThreadNode node, User user, String offset, String tags) {
private static String getViewThreadLink(String uri, ThreadNode node, User user, String offset,
String tags, String author) {
StringBuffer buf = new StringBuffer(64);
buf.append(uri);
if (node.getChildCount() > 0) {
@ -666,17 +734,21 @@ public class ViewThreadedServlet extends HttpServlet {
if (!empty(tags))
buf.append(ThreadedHTMLRenderer.PARAM_TAGS).append('=').append(tags).append('&');
if (!empty(author))
buf.append(ThreadedHTMLRenderer.PARAM_AUTHOR).append('=').append(author).append('&');
buf.append("#").append(node.getEntry().toString());
return buf.toString();
}
private String getFilterByTagLink(HttpServletRequest req, ThreadNode node, User user, String tag) {
return ThreadedHTMLRenderer.getFilterByTagLink(req.getRequestURI(), node, user, tag);
private String getFilterByTagLink(HttpServletRequest req, ThreadNode node, User user, String tag, String author) {
return ThreadedHTMLRenderer.getFilterByTagLink(req.getRequestURI(), node, user, tag, author);
}
private String getNavLink(HttpServletRequest req, int offset) {
return ThreadedHTMLRenderer.getNavLink(req.getRequestURI(),
return ThreadedHTMLRenderer.getNavLink(req.getRequestURI(),
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_POST),
req.getParameter(ThreadedHTMLRenderer.PARAM_VIEW_THREAD),
req.getParameter(ThreadedHTMLRenderer.PARAM_TAGS),
req.getParameter(ThreadedHTMLRenderer.PARAM_AUTHOR),
offset);
}
@ -763,22 +835,10 @@ public class ViewThreadedServlet extends HttpServlet {
"<link href=\"rss.jsp\" rel=\"alternate\" type=\"application/rss+xml\" >\n" +
"</head>\n" +
"<body>\n" +
"<span style=\"display: none\"><a href=\"#bodySubject\">Jump to the beginning of the first post rendered, if any</a>\n" +
"<a href=\"#threads\">Jump to the thread navigation</a>\n</span>\n" +
"<table border=\"0\" width=\"100%\" class=\"overallTable\">\n";
private static final String CONTROL_BAR_WITHOUT_TAGS = "<form>\n" +
"<tr class=\"controlBar\"><td colspan=\"2\">\n" +
"<!-- control bar begin -->\n" +
"Filter: <select disabled=\"true\" name=\"filter\">\n" +
" <option value=\"all\">All posts in all threads</option>\n" +
" <option value=\"self\">Threads you have posted in</option>\n" +
" <option value=\"favorites\">Threads your friends have posted in</option>\n" +
" </select>\n" +
"<input type=\"submit\" name=\"action\" value=\"Go\" />\n" +
"</td><td class=\"controlBarRight\"><a href=\"#threads\" title=\"Jump to the thread navigation\">Threads</a></td>\n" +
"<!-- control bar end -->\n" +
"</tr>\n" +
"</form>\n";
private static final String END_HTML = "</table>\n" +
"</body>\n";

View File

@ -301,6 +301,10 @@
<copy file="installer/resources/dnfb-header.ht" todir="pkg-temp/docs/" />
<copy file="installer/resources/dnfh-header.ht" todir="pkg-temp/docs/" />
<copy file="installer/resources/ahelper-conflict-header.ht" todir="pkg-temp/docs/" />
<mkdir dir="pkg-temp/docs/themes/" />
<copy todir="pkg-temp/docs/themes/" >
<fileset dir="installer/resources/themes/" />
</copy>
<mkdir dir="pkg-temp/eepsite" />
<mkdir dir="pkg-temp/eepsite/webapps" />
<mkdir dir="pkg-temp/eepsite/logs" />
@ -376,6 +380,12 @@
<copy file="installer/resources/dnfb-header.ht" todir="pkg-temp/docs/" />
<copy file="installer/resources/dnfh-header.ht" todir="pkg-temp/docs/" />
<copy file="installer/resources/ahelper-conflict-header.ht" todir="pkg-temp/docs/" />
<mkdir dir="pkg-temp/docs/themes/" />
<copy todir="pkg-temp/docs/themes/" >
<fileset dir="installer/resources/themes/" />
</copy>
<!-- the addressbook handles this for updates -->
<!-- <copy file="hosts.txt" todir="pkg-temp/" /> -->
<mkdir dir="pkg-temp/eepsite" />

View File

@ -4,8 +4,10 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Enumeration;
@ -163,6 +165,37 @@ public class FileUtil {
}
}
/**
* Dump the contents of the given path (relative to the root) to the output
* stream. The path must not go above the root, either - if it does, it will
* throw a FileNotFoundException
*/
public static void readFile(String path, String root, OutputStream out) throws IOException {
File rootDir = new File(root);
while (path.startsWith("/") && (path.length() > 0) )
path = path.substring(1);
if (path.length() <= 0) throw new FileNotFoundException("Not serving up the root dir");
File target = new File(rootDir, path);
if (!target.exists()) throw new FileNotFoundException("Requested file does not exist: " + path);
String targetStr = target.getCanonicalPath();
String rootDirStr = rootDir.getCanonicalPath();
if (!targetStr.startsWith(rootDirStr)) throw new FileNotFoundException("Requested file is outside the root dir: " + path);
byte buf[] = new byte[1024];
FileInputStream in = null;
try {
in = new FileInputStream(target);
int read = 0;
while ( (read = in.read(buf)) != -1)
out.write(buf, 0, read);
out.close();
} finally {
if (in != null)
in.close();
}
}
/** return true if it was copied successfully */
public static boolean copy(String source, String dest, boolean overwriteExisting) {
File src = new File(source);

View File

@ -1,25 +1,36 @@
$Id: history.txt,v 1.318 2005/11/11 06:29:16 jrandom Exp $
$Id: history.txt,v 1.319 2005/11/11 21:38:56 cervantes Exp $
2005-11-11 jrandom
* Add filtering threads by author to Syndie, populated with authors in the
user's addressbook
* When creating the default user, add
"http://syndiemedia.i2p/archive/archive.txt" to their addressbook,
configured to automatically pull updates. (what other archives should
be included?)
* Tiny servlet to help dole out the new routerconsole themes, and bundle
the installer/resources/themes/** into ./docs/themes/** on both install
and update.
2005-11-11 cervantes
* Initial pass of the routerconsole revamp, starting with I2PTunnel and
being progressively rolled out to other sections at later dates.
Featuring abstracted W3C strict XHTML1.0 markup, with CSS providing
layout and styling.
* Implemented console themes. Users can create their own themes by
creating css files in: {i2pdir}/docs/themes/console/{themename}/
and activating it using the routerconsole.theme={themename} advanced
config property. Look at the example incomplete "defCon1" theme.
Note: This is very much a work in progress. Folks might want to hold-off
creating their own skins until the markup has solidified.
* Added "routerconsole.javascript.disabled=true" to disable console
client-side scripting and "routerconsole.css.disabled=true" to remove
css styling (only rolled out in the i2ptunnel interface currently)
* Fixed long standing bug with i2ptunnel client and server edit screens
where tunnel count and depth properties would fail to save. Added
backup quantity and variance configuration options.
* Added basic accessibility support (key shortcuts, linear markup, alt and
title information and form labels).
* So far only tested on IE6, Firefox 1.0.6, Opera 8 and lynx.
* Initial pass of the routerconsole revamp, starting with I2PTunnel and
being progressively rolled out to other sections at later dates.
Featuring abstracted W3C strict XHTML1.0 markup, with CSS providing
layout and styling.
* Implemented console themes. Users can create their own themes by
creating css files in: {i2pdir}/docs/themes/console/{themename}/
and activating it using the routerconsole.theme={themename} advanced
config property. Look at the example incomplete "defCon1" theme.
Note: This is very much a work in progress. Folks might want to hold-off
creating their own skins until the markup has solidified.
* Added "routerconsole.javascript.disabled=true" to disable console
client-side scripting and "routerconsole.css.disabled=true" to remove
css styling (only rolled out in the i2ptunnel interface currently)
* Fixed long standing bug with i2ptunnel client and server edit screens
where tunnel count and depth properties would fail to save. Added
backup quantity and variance configuration options.
* Added basic accessibility support (key shortcuts, linear markup, alt and
title information and form labels).
* So far only tested on IE6, Firefox 1.0.6, Opera 8 and lynx.
2005-11-11 jrandom
* Default Syndie to single user mode, and automatically log into a default