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:
14
apps/routerconsole/jsp/viewtheme.jsp
Normal file
14
apps/routerconsole/jsp/viewtheme.jsp
Normal 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());
|
||||
%>
|
@ -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
|
||||
|
@ -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) ) {
|
||||
|
@ -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; }
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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("\"><< First Page</a> ");
|
||||
if (threadOffset == 0) {
|
||||
out.write("<< First Page ");
|
||||
} else {
|
||||
out.write("<a href=\"");
|
||||
out.write(getNavLink(req, 0));
|
||||
out.write("\"><< 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";
|
||||
|
||||
|
10
build.xml
10
build.xml
@ -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" />
|
||||
|
@ -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);
|
||||
|
51
history.txt
51
history.txt
@ -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
|
||||
|
Reference in New Issue
Block a user