2006-01-08 jrandom

* First pass of the new blog interface, though without much of the useful
      customization features (coming soon)
This commit is contained in:
jrandom
2006-01-08 20:54:36 +00:00
committed by zzz
parent 97dae94b46
commit 894caaa63c
14 changed files with 1357 additions and 19 deletions

View File

@ -57,6 +57,7 @@ public class BlogInfo {
public static final String DESCRIPTION = "Description";
public static final String CONTACT_URL = "ContactURL";
public static final String EDITION = "Edition";
public static final String SUMMARY_ENTRY_ID = "SummaryEntryId";
public void load(InputStream in) throws IOException {
Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());

View File

@ -0,0 +1,127 @@
package net.i2p.syndie.data;
import java.io.*;
import java.util.*;
import net.i2p.client.naming.PetName;
import net.i2p.data.DataHelper;
/**
* Contain the current supplementary data for rendering a blog, as opposed to
* just verifying and rendering a post.
*/
public class BlogInfoData {
private BlogURI _dataEntryId;
/** list of List of PetName instances that the blog refers to */
private List _referenceGroups;
/** customized style config */
private Properties _styleOverrides;
/** the blog's logo */
private Attachment _logo;
private List _otherAttachments;
public static final String ATTACHMENT_LOGO = "logo.png";
public static final String ATTACHMENT_REFERENCE_GROUPS = "groups.txt";
public static final String ATTACHMENT_STYLE_OVERRIDE = "style.cfg";
/** identifies a post as being a blog info data, not a content bearing post */
public static final String TAG = "BlogInfoData";
public BlogInfoData() {}
public BlogURI getEntryId() { return _dataEntryId; }
public boolean isLogoSpecified() { return _logo != null; }
public Attachment getLogo() { return _logo; }
public boolean isStyleSpecified() { return _styleOverrides != null; }
public Properties getStyleOverrides() { return _styleOverrides; }
public int getReferenceGroupCount() { return _referenceGroups != null ? _referenceGroups.size() : 0; }
/** list of PetName elements to be included in the list */
public List getReferenceGroup(int groupNum) { return (List)_referenceGroups.get(groupNum); }
public int getOtherAttachmentCount() { return _otherAttachments != null ? _otherAttachments.size() : 0; }
public Attachment getOtherAttachment(int num) { return (Attachment)_otherAttachments.get(num); }
public Attachment getOtherAttachment(String name) {
for (int i = 0; i < _otherAttachments.size(); i++) {
Attachment a = (Attachment)_otherAttachments.get(i);
if (a.getName().equals(name))
return a;
}
return null;
}
public void writeLogo(OutputStream out) throws IOException {
InputStream in = null;
try {
in = _logo.getDataStream();
byte buf[] = new byte[4096];
int read = 0;
while ( (read = in.read(buf)) != -1)
out.write(buf, 0, read);
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
}
}
public void load(EntryContainer entry) throws IOException {
_dataEntryId = entry.getURI();
Attachment attachments[] = entry.getAttachments();
for (int i = 0; i < attachments.length; i++) {
if (ATTACHMENT_LOGO.equals(attachments[i].getName())) {
_logo = attachments[i];
} else if (ATTACHMENT_REFERENCE_GROUPS.equals(attachments[i].getName())) {
readReferenceGroups(attachments[i]);
} else if (ATTACHMENT_STYLE_OVERRIDE.equals(attachments[i].getName())) {
readStyleOverride(attachments[i]);
} else {
if (_otherAttachments == null)
_otherAttachments = new ArrayList();
_otherAttachments.add(attachments[i]);
}
}
}
private void readReferenceGroups(Attachment att) throws IOException {
InputStream in = null;
try {
in = att.getDataStream();
StringBuffer line = new StringBuffer(128);
List groups = new ArrayList();
String prevGroup = null;
List defaultGroup = new ArrayList();
while (true) {
boolean ok = DataHelper.readLine(in, line);
if (line.length() > 0) {
PetName pn = new PetName(line.toString().trim());
if (pn.getGroupCount() <= 0) {
defaultGroup.add(pn);
} else if (pn.getGroup(0).equals(prevGroup)) {
List curGroup = (List)groups.get(groups.size()-1);
curGroup.add(pn);
} else {
List curGroup = new ArrayList();
curGroup.add(pn);
groups.add(curGroup);
prevGroup = pn.getGroup(0);
}
}
if (!ok)
break;
}
if (defaultGroup.size() > 0)
groups.add(defaultGroup);
_referenceGroups = groups;
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
}
}
private void readStyleOverride(Attachment att) throws IOException {
InputStream in = null;
try {
in = att.getDataStream();
Properties props = new Properties();
DataHelper.loadProps(props, in);
_styleOverrides = props;
} finally {
if (in != null) try { in.close(); } catch (IOException ioe) {}
}
}
}

View File

@ -59,7 +59,10 @@ public class EntryContainer {
public EntryContainer(BlogURI uri, String tags[], byte smlData[]) {
this();
_entryURI = uri;
_entryData = new Entry(DataHelper.getUTF8(smlData));
if ( (smlData == null) || (smlData.length <= 0) )
_entryData = new Entry(null);
else
_entryData = new Entry(DataHelper.getUTF8(smlData));
setHeader(HEADER_BLOGKEY, Base64.encode(uri.getKeyHash().getData()));
StringBuffer buf = new StringBuffer();
for (int i = 0; tags != null && i < tags.length; i++)
@ -203,10 +206,13 @@ public class EntryContainer {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ZipOutputStream out = new ZipOutputStream(baos);
ZipEntry ze = new ZipEntry(ZIP_ENTRY);
byte data[] = DataHelper.getUTF8(_entryData.getText());
byte data[] = null;
if (_entryData.getText() != null)
data = DataHelper.getUTF8(_entryData.getText());
ze.setTime(0);
out.putNextEntry(ze);
out.write(data);
if (data != null)
out.write(data);
out.closeEntry();
for (int i = 0; (_attachments != null) && (i < _attachments.length); i++) {
ze = new ZipEntry(ZIP_ATTACHMENT_PREFIX + i + ZIP_ATTACHMENT_SUFFIX);
@ -270,6 +276,9 @@ public class EntryContainer {
//System.out.println("Read entry [" + name + "] with size=" + entryData.length);
}
if (_entryData == null)
_entryData = new Entry(null);
_attachments = new Attachment[attachments.size()];
for (int i = 0; i < attachments.size(); i++) {

View File

@ -0,0 +1,189 @@
package net.i2p.syndie.sml;
import java.io.*;
import java.util.*;
import net.i2p.I2PAppContext;
import net.i2p.client.naming.PetName;
import net.i2p.data.*;
import net.i2p.syndie.data.*;
import net.i2p.syndie.web.*;
/**
* Renders posts for display within the blog view
*
*/
public class BlogRenderer extends HTMLRenderer {
private BlogInfo _blog;
private BlogInfoData _data;
public BlogRenderer(I2PAppContext ctx, BlogInfo info, BlogInfoData data) {
super(ctx);
_blog = info;
_data = data;
}
public void receiveHeaderEnd() {
_preBodyBuffer.append("<div class=\"syndieBlogPost\"><hr style=\"display: none\" />\n");
_preBodyBuffer.append("<div class=\"syndieBlogPostHeader\">\n");
_preBodyBuffer.append("<div class=\"syndieBlogPostSubject\">");
String subject = (String)_headers.get(HEADER_SUBJECT);
if (subject == null)
subject = "[no subject]";
String tags[] = _entry.getTags();
for (int i = 0; (tags != null) && (i < tags.length); i++)
displayTag(_preBodyBuffer, _data, tags[i]);
_preBodyBuffer.append(getSpan("subjectText")).append(sanitizeString(subject)).append("</span></div>\n");
String name = getAuthor();
String when = getEntryDate(_entry.getURI().getEntryId());
_preBodyBuffer.append("<div class=\"syndieBlogPostFrom\">Posted by: <a href=\"");
_preBodyBuffer.append(getMetadataURL(_entry.getURI().getKeyHash()));
_preBodyBuffer.append("\" title=\"View their profile\">");
_preBodyBuffer.append(sanitizeString(name));
_preBodyBuffer.append("</a> on ");
_preBodyBuffer.append(when);
_preBodyBuffer.append("</div>\n");
_preBodyBuffer.append("</div><!-- end syndieBlogPostHeader -->\n");
_preBodyBuffer.append("<div class=\"syndieBlogPostSummary\">\n");
}
public void receiveEnd() {
_postBodyBuffer.append("</div><!-- end syndieBlogPostSummary -->\n");
_postBodyBuffer.append("<div class=\"syndieBlogPostDetails\">\n");
int childCount = getChildCount(_archive.getIndex().getThreadedIndex().getNode(_entry.getURI()));
if ( (_cutReached || childCount > 0) && (_cutBody) ) {
_postBodyBuffer.append("<a href=\"");
_postBodyBuffer.append(getEntryURL()).append("\" title=\"View comments on this post\">Read more</a> ");
}
if (childCount > 0) {
_postBodyBuffer.append(childCount).append(" ");
if (childCount > 1)
_postBodyBuffer.append(" comments already, ");
else
_postBodyBuffer.append(" comment already, ");
}
_postBodyBuffer.append("<a href=\"");
_postBodyBuffer.append(getReplyURL()).append("\" title=\"Reply to this post\">Leave a comment</a>\n");
_postBodyBuffer.append("</div><!-- end syndieBlogPostDetails -->\n");
_postBodyBuffer.append("</div><!-- end syndieBlogPost -->\n\n");
}
private int getChildCount(ThreadNode node) {
int nodes = 0;
for (int i = 0; i < node.getChildCount(); i++) {
nodes++;
nodes += getChildCount(node.getChild(i));
}
return nodes;
}
private String getAuthor() {
PetName pn = null;
if ( (_entry != null) && (_user != null) )
pn = _user.getPetNameDB().getByLocation(_entry.getURI().getKeyHash().toBase64());
if (pn != null)
return pn.getName();
BlogInfo info = null;
if (_entry != null) {
info = _archive.getBlogInfo(_entry.getURI());
if (info != null) {
String str = info.getProperty(BlogInfo.NAME);
if (str != null)
return str;
}
return _entry.getURI().getKeyHash().toBase64().substring(0,6);
} else {
return "No name?";
}
}
private void displayTag(StringBuffer buf, BlogInfoData data, String tag) {
//buf.append("<a href=\"");
//buf.append(getPageURL(_blog.getKey().calculateHash(), tag, -1, null, 5, 0, false, true));
//buf.append("\" title=\"Filter the blog by the tag '").append(sanitizeTagParam(tag)).append("'\">");
if ( (tag == null) || ("[none]".equals(tag) ) )
return;
buf.append("<img src=\"").append(getTagIconURL(tag)).append("\" alt=\"");
buf.append(sanitizeTagParam(tag)).append("\" />");
//buf.append("</a>");
buf.append(" ");
}
public String getMetadataURL(Hash blog) { return ThreadedHTMLRenderer.buildProfileURL(blog); }
private String getTagIconURL(String tag) {
return "viewicon.jsp?tag=" + Base64.encode(tag) + "&amp;" +
ViewBlogServlet.PARAM_BLOG + "=" + _blog.getKey().calculateHash().toBase64();
}
private String getReplyURL() {
String subject = (String)_headers.get(HEADER_SUBJECT);
if (subject != null) {
if (!subject.startsWith("re:"))
subject = "re: " + subject;
} else {
subject = "re: ";
}
return "post.jsp?" + PostServlet.PARAM_PARENT + "="
+ Base64.encode(_entry.getURI().getKeyHash().toBase64() + "/" + _entry.getURI().getEntryId()) + "&amp;"
+ PostServlet.PARAM_SUBJECT + "=" + sanitizeTagParam(subject) + "&amp;";
}
protected String getEntryURL() { return getEntryURL(_user != null ? _user.getShowImages() : true); }
protected String getEntryURL(boolean showImages) {
if (_entry == null) return "unknown";
return "blog.jsp?"
+ ViewBlogServlet.PARAM_BLOG + "=" + _blog.getKey().calculateHash().toBase64() + "&amp;"
+ ViewBlogServlet.PARAM_ENTRY + "="
+ Base64.encode(_entry.getURI().getKeyHash().getData()) + '/' + _entry.getURI().getEntryId();
}
protected String getAttachmentURLBase() {
return "invalid";
}
protected String getAttachmentURL(int id) {
if (_entry == null) return "unknown";
return "blog.jsp?"
+ ViewBlogServlet.PARAM_BLOG + "=" + _blog.getKey().calculateHash().toBase64() + "&amp;"
+ ViewBlogServlet.PARAM_ATTACHMENT + "="
+ Base64.encode(_entry.getURI().getKeyHash().getData()) + "/"
+ _entry.getURI().getEntryId() + "/"
+ id;
}
public String getPageURL(String entry) {
StringBuffer buf = new StringBuffer(128);
buf.append("blog.jsp?");
buf.append(ViewBlogServlet.PARAM_BLOG).append(_blog.getKey().calculateHash().toBase64()).append("&amp;");
if (entry != null) {
if (entry.startsWith("entry://"))
entry = entry.substring("entry://".length());
else if (entry.startsWith("blog://"))
entry = entry.substring("blog://".length());
int split = entry.indexOf('/');
if (split > 0) {
buf.append(ViewBlogServlet.PARAM_ENTRY).append("=");
buf.append(sanitizeTagParam(entry.substring(0, split))).append('/');
buf.append(sanitizeTagParam(entry.substring(split+1))).append("&amp;");
}
}
return buf.toString();
}
public String getPageURL(Hash blog, String tag, long entryId, String group, int numPerPage, int pageNum, boolean expandEntries, boolean showImages) {
StringBuffer buf = new StringBuffer(128);
buf.append("blog.jsp?");
buf.append(ViewBlogServlet.PARAM_BLOG).append("=");
buf.append(_blog.getKey().calculateHash().toBase64()).append("&amp;");
if ( (blog != null) && (entryId > 0) ) {
buf.append(ViewBlogServlet.PARAM_ENTRY).append("=");
buf.append(blog.toBase64()).append('/');
buf.append(entryId).append("&amp;");
}
if (tag != null)
buf.append(ViewBlogServlet.PARAM_TAG).append('=').append(sanitizeTagParam(tag)).append("&amp;");
if ( (pageNum >= 0) && (numPerPage > 0) )
buf.append(ViewBlogServlet.PARAM_OFFSET).append('=').append(pageNum*numPerPage).append("&amp;");
return buf.toString();
}
}

View File

@ -8,7 +8,7 @@ import net.i2p.util.Log;
*
*/
public class EventReceiverImpl implements SMLParser.EventReceiver {
private I2PAppContext _context;
protected I2PAppContext _context;
private Log _log;
public EventReceiverImpl(I2PAppContext ctx) {

View File

@ -1017,10 +1017,10 @@ public class HTMLRenderer extends EventReceiverImpl {
_entry.getURI().getEntryId();
}
protected String getAttachmentURLBase() { return "viewattachment.jsp"; }
protected String getAttachmentURLBase() { return "viewattachment.jsp?"; }
protected String getAttachmentURL(int id) {
if (_entry == null) return "unknown";
return getAttachmentURLBase() + "?" +
return getAttachmentURLBase() +
ArchiveViewerBean.PARAM_BLOG + "=" +
Base64.encode(_entry.getURI().getKeyHash().getData()) +
"&" + ArchiveViewerBean.PARAM_ENTRY + "=" + _entry.getURI().getEntryId() +

View File

@ -596,9 +596,11 @@ public class ArchiveViewerBean {
}
public static void renderAttachment(Map parameters, OutputStream out) throws IOException {
Attachment a = getAttachment(parameters);
renderAttachment(getAttachment(parameters), out);
}
public static void renderAttachment(Attachment a, OutputStream out) throws IOException {
if (a == null) {
renderInvalidAttachment(parameters, out);
renderInvalidAttachment(out);
} else {
InputStream data = a.getDataStream();
byte buf[] = new byte[1024];
@ -610,17 +612,21 @@ public class ArchiveViewerBean {
}
public static final String getAttachmentContentType(Map parameters) {
Attachment a = getAttachment(parameters);
if (a == null)
return getAttachmentContentType(getAttachment(parameters));
}
public static final String getAttachmentContentType(Attachment attachment) {
if (attachment == null)
return "text/html";
String mime = a.getMimeType();
String mime = attachment.getMimeType();
if ( (mime != null) && ((mime.startsWith("image/") || mime.startsWith("text/plain"))) )
return mime;
return "application/octet-stream";
}
public static final boolean getAttachmentShouldShowInline(Map parameters) {
Attachment a = getAttachment(parameters);
return getAttachmentShouldShowInline(getAttachment(parameters));
}
public static final boolean getAttachmentShouldShowInline(Attachment a) {
if (a == null)
return true;
String mime = a.getMimeType();
@ -631,7 +637,9 @@ public class ArchiveViewerBean {
}
public static final int getAttachmentContentLength(Map parameters) {
Attachment a = getAttachment(parameters);
return getAttachmentContentLength(getAttachment(parameters));
}
public static final int getAttachmentContentLength(Attachment a) {
if (a != null)
return a.getDataLength();
else
@ -639,7 +647,9 @@ public class ArchiveViewerBean {
}
public static final String getAttachmentFilename(Map parameters) {
Attachment a = getAttachment(parameters);
return getAttachmentFilename(getAttachment(parameters));
}
public static final String getAttachmentFilename(Attachment a) {
if (a != null)
return a.getName();
else
@ -667,7 +677,7 @@ public class ArchiveViewerBean {
return null;
}
private static void renderInvalidAttachment(Map parameters, OutputStream out) throws IOException {
private static void renderInvalidAttachment(OutputStream out) throws IOException {
out.write(DataHelper.getUTF8("<span class=\"b_msgErr\">No such entry, or no such attachment</span>"));
}

View File

@ -0,0 +1,270 @@
package net.i2p.syndie.web;
import java.io.*;
import java.util.*;
import net.i2p.I2PAppContext;
import net.i2p.client.naming.PetName;
import net.i2p.data.DataHelper;
import net.i2p.syndie.*;
import net.i2p.syndie.data.*;
import net.i2p.util.Log;
/**
*
*/
public class BlogConfigBean {
private I2PAppContext _context;
private Log _log;
private User _user;
private String _title;
private String _description;
private String _contactInfo;
/** list of list of PetNames */
private List _groups;
private Properties _styleOverrides;
private File _logo;
private boolean _loaded;
private boolean _updated;
public BlogConfigBean() {
_context = I2PAppContext.getGlobalContext();
_log = _context.logManager().getLog(BlogConfigBean.class);
_groups = new ArrayList();
_styleOverrides = new Properties();
}
public User getUser() { return _user; }
public void setUser(User user) {
_user = user;
_title = null;
_description = null;
_contactInfo = null;
_groups.clear();
_styleOverrides.clear();
if (_logo != null)
_logo.delete();
_logo = null;
_loaded = false;
_updated = false;
load();
}
public String getTitle() { return _title; }
public void setTitle(String title) {
_title = title;
_updated = true;
}
public String getDescription() { return _description; }
public void setDescription(String desc) {
_description = desc;
_updated = true;
}
public String getContactInfo() { return _contactInfo; }
public void setContactInfo(String info) {
_contactInfo = info;
_updated = true;
}
public int getGroupCount() { return _groups.size(); }
/** gets the actual modifiable list of PetName instances */
public List getGroup(int i) { return (List)_groups.get(i); }
/** gets the actual modifiable list of PetName instances */
public List getGroup(String name) {
for (int i = 0; i < _groups.size(); i++) {
List grp = (List)_groups.get(i);
if (grp.size() > 0) {
PetName pn = (PetName)grp.get(0);
if ( (pn.getGroupCount() == 0) && ( (name == null) || (name.length() <= 0) ) )
return grp;
String curGroup = pn.getGroup(0);
if (curGroup.equals(name))
return grp;
}
}
return null;
}
/** adds the given element to the appropriate group (creating a new one if necessary) */
public void add(PetName pn) {
String groupName = null;
if (pn.getGroupCount() > 0)
groupName = pn.getGroup(0);
List group = getGroup(groupName);
if (group == null) {
group = new ArrayList(4);
group.add(pn);
_groups.add(group);
} else {
group.add(pn);
}
}
public void remove(PetName pn) {
String groupName = null;
if (pn.getGroupCount() > 0)
groupName = pn.getGroup(0);
List group = getGroup(groupName);
if (group != null) {
group.remove(pn);
if (group.size() <= 0)
_groups.remove(group);
}
}
public void remove(String name) {
for (int i = 0; i < getGroupCount(); i++) {
List group = getGroup(i);
for (int j = 0; j < group.size(); j++) {
PetName pn = (PetName)group.get(j);
if (pn.getName().equals(name)) {
group.remove(j);
if (group.size() <= 0)
_groups.remove(group);
return;
}
}
}
}
/** take note that the groups have been updated in some way (reordered, etc) */
public void groupsUpdated() { _updated = true; }
public String getStyleOverride(String prop) { return _styleOverrides.getProperty(prop); }
public void setStyleOverride(String prop, String val) {
_styleOverrides.setProperty(prop, val);
_updated = true;
}
public void unsetStyleOverride(String prop) {
_styleOverrides.remove(prop);
_updated = true;
}
public File getLogo() { return _logo; }
public void setLogo(File logo) {
if ( (logo != null) && (logo.length() > 128*1024) ) {
_log.error("Refusing a logo more than 128KB");
return;
}
_logo = logo;
_updated = true;
}
public boolean hasPendingChanges() { return _updated; }
private void load() {
Archive archive = BlogManager.instance().getArchive();
BlogInfo info = archive.getBlogInfo(_user.getBlog());
if (info != null) {
_title = info.getProperty(BlogInfo.NAME);
_description = info.getProperty(BlogInfo.DESCRIPTION);
_contactInfo = info.getProperty(BlogInfo.CONTACT_URL);
String id = info.getProperty(BlogInfo.SUMMARY_ENTRY_ID);
if (id != null) {
BlogURI uri = new BlogURI(id);
EntryContainer entry = archive.getEntry(uri);
if (entry != null) {
BlogInfoData data = new BlogInfoData();
try {
data.load(entry);
if (data.isLogoSpecified()) {
File logo = File.createTempFile("logo", ".png", BlogManager.instance().getTempDir());
FileOutputStream os = null;
try {
os = new FileOutputStream(logo);
data.writeLogo(os);
_logo = logo;
} finally {
if (os != null) try { os.close(); } catch (IOException ioe) {}
}
}
for (int i = 0; i < data.getReferenceGroupCount(); i++) {
List group = (List)data.getReferenceGroup(i);
for (int j = 0; j < group.size(); j++) {
PetName pn = (PetName)group.get(j);
add(pn);
}
}
_styleOverrides.putAll(data.getStyleOverrides());
} catch (IOException ioe) {
_log.warn("Unable to load the blog info data from " + uri, ioe);
}
}
}
}
_loaded = true;
}
public boolean publishChanges() throws IOException {
FileInputStream logo = null;
try {
if (_logo != null)
logo = new FileInputStream(_logo);
InputStream styleStream = createStyleStream();
InputStream groupStream = createGroupStream();
String tags = BlogInfoData.TAG;
String subject = "n/a";
String headers = "";
String sml = "";
List filenames = new ArrayList();
List filestreams = new ArrayList();
List filetypes = new ArrayList();
if (logo != null) {
filenames.add(BlogInfoData.ATTACHMENT_LOGO);
filestreams.add(logo);
filetypes.add("image/png");
}
filenames.add(BlogInfoData.ATTACHMENT_STYLE_OVERRIDE);
filestreams.add(styleStream);
filetypes.add("text/plain");
filenames.add(BlogInfoData.ATTACHMENT_REFERENCE_GROUPS);
filestreams.add(groupStream);
filetypes.add("text/plain");
BlogURI uri = BlogManager.instance().createBlogEntry(_user, subject, tags, headers, sml,
filenames, filestreams, filetypes);
if (uri != null) {
Archive archive = BlogManager.instance().getArchive();
BlogInfo info = archive.getBlogInfo(_user.getBlog());
if (info != null) {
String props[] = info.getProperties();
Properties opts = new Properties();
for (int i = 0; i < props.length; i++) {
if (!props[i].equals(BlogInfo.SUMMARY_ENTRY_ID))
opts.setProperty(props[i], info.getProperty(props[i]));
}
opts.setProperty(BlogInfo.SUMMARY_ENTRY_ID, uri.toString());
boolean updated = BlogManager.instance().updateMetadata(_user, _user.getBlog(), opts);
if (updated) {
// ok great, published locally, though should we push it to others?
_log.info("Blog summary updated for " + _user + " in " + uri.toString());
return true;
}
} else {
_log.error("Info is not known for " + _user.getBlog().toBase64());
return false;
}
} else {
_log.error("Error creating the summary entry");
return false;
}
} finally {
if (logo != null) try { logo.close(); } catch (IOException ioe) {}
// the other streams are in-memory, drop with the scope
}
return false;
}
private InputStream createStyleStream() throws IOException {
StringBuffer buf = new StringBuffer(1024);
if (_styleOverrides != null) {
for (Iterator iter = _styleOverrides.keySet().iterator(); iter.hasNext(); ) {
String key = (String)iter.next();
String val = _styleOverrides.getProperty(key);
buf.append(key).append('=').append(val).append('\n');
}
}
return new ByteArrayInputStream(DataHelper.getUTF8(buf));
}
private InputStream createGroupStream() throws IOException {
StringBuffer buf = new StringBuffer(1024);
for (int i = 0; i < _groups.size(); i++) {
List group = (List)_groups.get(i);
for (int j = 0; j < group.size(); j++) {
PetName pn = (PetName)group.get(j);
buf.append(pn.toString()).append('\n');
}
}
return new ByteArrayInputStream(DataHelper.getUTF8(buf));
}
}

View File

@ -0,0 +1,231 @@
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 javax.servlet.ServletException;
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.*;
/**
* Display our blog config, and let us edit it through several screens
*
*/
public class BlogConfigServlet extends BaseServlet {
private static final String ATTR_CONFIG_BEAN = "__blogConfigBean";
public static final String PARAM_CONFIG_SCREEN = "screen";
public static final String SCREEN_GENERAL = "general";
public static final String SCREEN_REFERENCES = "references";
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
if ( (user == null) || (!user.getAuthenticated() && !BlogManager.instance().isSingleUser())) {
out.write("You must be logged in to edit your profile");
return;
}
BlogConfigBean bean = (BlogConfigBean)req.getSession().getAttribute(ATTR_CONFIG_BEAN);
if (bean == null) {
bean = new BlogConfigBean();
bean.setUser(user);
}
// handle actions here...
// on done handling
String screen = req.getParameter(PARAM_CONFIG_SCREEN);
if (screen == null)
screen = SCREEN_GENERAL;
out.write("todo: Display screen " + screen);
/*
if (SCREEN_REFERENCES.equals(screen)) {
displayReferencesScreen(req, out, bean);
} else {
displayGeneralScreen(req, out, bean);
}
*/
}
/*
private void renderMyProfile(User user, String baseURI, PrintWriter out, Archive archive) throws IOException {
BlogInfo info = archive.getBlogInfo(user.getBlog());
if (info == null)
return;
out.write("<!-- " + info.toString() + "-->\n");
out.write("<form action=\"" + baseURI + "\" method=\"POST\">\n");
writeAuthActionFields(out);
// now add the form to update
out.write("<tr><td colspan=\"3\">Your profile</td></tr>\n");
out.write("<tr><td colspan=\"3\">Name: <input type=\"text\" name=\""
+ ThreadedHTMLRenderer.PARAM_PROFILE_NAME + "\" value=\""
+ HTMLRenderer.sanitizeTagParam(info.getProperty(BlogInfo.NAME)) + "\"></td></tr>\n");
out.write("<tr><td colspan=\"3\">Account description: <input type=\"text\" name=\""
+ ThreadedHTMLRenderer.PARAM_PROFILE_DESC + "\" value=\""
+ HTMLRenderer.sanitizeTagParam(info.getProperty(BlogInfo.DESCRIPTION)) + "\"></td></tr>\n");
out.write("<tr><td colspan=\"3\">Contact information: <input type=\"text\" name=\""
+ ThreadedHTMLRenderer.PARAM_PROFILE_URL + "\" value=\""
+ HTMLRenderer.sanitizeTagParam(info.getProperty(BlogInfo.CONTACT_URL)) + "\"></td></tr>\n");
out.write("<tr><td colspan=\"3\">Other attributes:<br /><textarea rows=\"3\" name=\""
+ ThreadedHTMLRenderer.PARAM_PROFILE_OTHER + "\" cols=\"60\">");
String props[] = info.getProperties();
if (props != null) {
for (int i = 0; i < props.length; i++) {
if (!BlogInfo.NAME.equals(props[i]) &&
!BlogInfo.DESCRIPTION.equals(props[i]) &&
!BlogInfo.EDITION.equals(props[i]) &&
!BlogInfo.OWNER_KEY.equals(props[i]) &&
!BlogInfo.POSTERS.equals(props[i]) &&
!BlogInfo.SIGNATURE.equals(props[i]) &&
!BlogInfo.CONTACT_URL.equals(props[i])) {
out.write(HTMLRenderer.sanitizeString(props[i], false) + ": "
+ HTMLRenderer.sanitizeString(info.getProperty(props[i]), false) + "\n");
}
}
}
out.write("</textarea></td></tr>\n");
if (user.getAuthenticated()) {
if ( (user.getUsername() == null) || (user.getUsername().equals(BlogManager.instance().getDefaultLogin())) ) {
// this is the default user, don't let them change the password
} else {
out.write("<tr><td colspan=\"3\">Old Password: <input type=\"password\" name=\"oldPassword\" /></td></tr>\n");
out.write("<tr><td colspan=\"3\">Password: <input type=\"password\" name=\"password\" /></td></tr>\n");
out.write("<tr><td colspan=\"3\">Password again: <input type=\"password\" name=\"passwordConfirm\" /></td></tr>\n");
}
if (!BlogManager.instance().authorizeRemote(user)) {
out.write("<tr><td colspan=\"3\">To access the remote functionality, please specify the administrative password: <br />\n" +
"<input type=\"password\" name=\"adminPass\" /></td></tr>\n");
}
}
out.write("<tr><td colspan=\"3\"><input type=\"submit\" name=\"action\" value=\"Update profile\" /></td></tr>\n");
out.write("</form>\n");
}
private void renderProfile(User user, String baseURI, PrintWriter out, Hash author, Archive archive) throws IOException {
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());
name = null;
if (info != null)
name = info.getProperty(BlogInfo.NAME);
if ( (name == null) || (name.trim().length() <= 0) )
name = author.toBase64().substring(0, 6);
out.write(" (" + name + ")");
} else {
if (info != null)
name = info.getProperty(BlogInfo.NAME);
if ( (name == null) || (name.trim().length() <= 0) )
name = author.toBase64().substring(0, 6);
out.write(name);
}
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");
if (pn == null) {
out.write("<tr><td colspan=\"3\">Not currently bookmarked. Add them to your ");
String addFav = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_FAVORITE,
baseURI, "", "", "", "", "", author.toBase64());
String addIgnore = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_IGNORE,
baseURI, "", "", "", "", "", author.toBase64());
out.write("<a href=\"" + addFav + "\" title=\"Threads by favorite authors are shown specially\">favorites</a> or ");
out.write("<a href=\"" + addIgnore + "\" title=\"Threads by ignored authors are hidden from view\">ignored</a> ");
out.write("</td></tr>\n");
} else if (pn.isMember(FilteredThreadIndex.GROUP_IGNORE)) {
out.write("<tr><td colspan=\"3\">Currently ignored - threads they create are hidden.</td></tr>\n");
String remIgnore = getRemoveFromGroupLink(user, pn.getName(), FilteredThreadIndex.GROUP_IGNORE,
baseURI, "", "", "", "", "", author.toBase64());
out.write("<tr><td colspan=\"3\"><a href=\"" + remIgnore + "\">Unignore " + pn.getName() + "</a></td></tr>\n");
String remCompletely = getRemoveFromGroupLink(user, pn.getName(), "",
baseURI, "", "", "", "", "", author.toBase64());
out.write("<tr><td colspan=\"3\"><a href=\"" + remCompletely + "\">Forget about " + pn.getName() + " entirely</a></td></tr>\n");
} else if (pn.isMember(FilteredThreadIndex.GROUP_FAVORITE)) {
out.write("<tr><td colspan=\"3\">Currently marked as a favorite author - threads they participate in " +
"are highlighted.</td></tr>\n");
String remIgnore = getRemoveFromGroupLink(user, pn.getName(), FilteredThreadIndex.GROUP_FAVORITE,
baseURI, "", "", "", "", "", author.toBase64());
out.write("<tr><td colspan=\"3\"><a href=\"" + remIgnore + "\">Remove " + pn.getName() + " from the list of favorite authors</a></td></tr>\n");
String addIgnore = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_IGNORE,
baseURI, "", "", "", "", "", author.toBase64());
out.write("<tr><td colspan=\"3\"><a href=\"" + addIgnore + "\" title=\"Threads by ignored authors are hidden from view\">Ignore the author</a></td></tr>");
String remCompletely = getRemoveFromGroupLink(user, pn.getName(), "",
baseURI, "", "", "", "", "", author.toBase64());
out.write("<tr><td colspan=\"3\"><a href=\"" + remCompletely + "\">Forget about " + pn.getName() + " entirely</a></td></tr>\n");
} else {
out.write("<tr><td colspan=\"3\">Currently bookmarked. Add them to your ");
String addFav = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_FAVORITE,
baseURI, "", "", "", "", "", author.toBase64());
String addIgnore = getAddToGroupLink(user, author, FilteredThreadIndex.GROUP_IGNORE,
baseURI, "", "", "", "", "", author.toBase64());
out.write("<a href=\"" + addFav + "\" title=\"Threads by favorite authors are shown specially\">favorites</a> or ");
out.write("<a href=\"" + addIgnore + "\" title=\"Threads by ignored authors are hidden from view\">ignored</a> list</td></tr>");
String remCompletely = getRemoveFromGroupLink(user, pn.getName(), "",
baseURI, "", "", "", "", "", author.toBase64());
out.write("<tr><td colspan=\"3\"><a href=\"" + remCompletely + "\">Forget about " + pn.getName() + " entirely</a></td></tr>\n");
}
if (info != null) {
String descr = info.getProperty(BlogInfo.DESCRIPTION);
if ( (descr != null) && (descr.trim().length() > 0) )
out.write("<tr><td colspan=\"3\">Account description: " + HTMLRenderer.sanitizeString(descr) + "</td></tr>\n");
String contactURL = info.getProperty(BlogInfo.CONTACT_URL);
if ( (contactURL != null) && (contactURL.trim().length() > 0) )
out.write("<tr><td colspan=\"3\">Contact information: "
+ HTMLRenderer.sanitizeString(contactURL) + "</td></tr>\n");
String props[] = info.getProperties();
int altCount = 0;
if (props != null)
for (int i = 0; i < props.length; i++)
if (!BlogInfo.NAME.equals(props[i]) &&
!BlogInfo.DESCRIPTION.equals(props[i]) &&
!BlogInfo.EDITION.equals(props[i]) &&
!BlogInfo.OWNER_KEY.equals(props[i]) &&
!BlogInfo.POSTERS.equals(props[i]) &&
!BlogInfo.SIGNATURE.equals(props[i]) &&
!BlogInfo.CONTACT_URL.equals(props[i]))
altCount++;
if (altCount > 0) {
for (int i = 0; i < props.length; i++) {
if (!BlogInfo.NAME.equals(props[i]) &&
!BlogInfo.DESCRIPTION.equals(props[i]) &&
!BlogInfo.EDITION.equals(props[i]) &&
!BlogInfo.OWNER_KEY.equals(props[i]) &&
!BlogInfo.POSTERS.equals(props[i]) &&
!BlogInfo.SIGNATURE.equals(props[i]) &&
!BlogInfo.CONTACT_URL.equals(props[i])) {
out.write("<tr><td colspan=\"3\">");
out.write(HTMLRenderer.sanitizeString(props[i]) + ": "
+ HTMLRenderer.sanitizeString(info.getProperty(props[i])));
out.write("</td></tr>\n");
}
}
}
}
}
*/
protected String getTitle() { return "Syndie :: Configure blog"; }
}

View File

@ -59,7 +59,7 @@ public class ProfileServlet extends BaseServlet {
out.write("<form action=\"" + baseURI + "\" method=\"POST\">\n");
writeAuthActionFields(out);
// now add the form to update
out.write("<tr><td colspan=\"3\">Your profile</td></tr>\n");
out.write("<tr><td colspan=\"3\">Your profile (<a href=\"configblog.jsp\">configure your blog</a>)</td></tr>\n");
out.write("<tr><td colspan=\"3\">Name: <input type=\"text\" name=\""
+ ThreadedHTMLRenderer.PARAM_PROFILE_NAME + "\" value=\""
+ HTMLRenderer.sanitizeTagParam(info.getProperty(BlogInfo.NAME)) + "\"></td></tr>\n");

View File

@ -0,0 +1,478 @@
package net.i2p.syndie.web;
import java.io.*;
import java.util.*;
import javax.servlet.ServletException;
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.*;
import net.i2p.util.FileUtil;
import net.i2p.util.Log;
/**
* Render the appropriate posts for the current blog, using any blog info data available
*
*/
public class ViewBlogServlet extends BaseServlet {
public static final String PARAM_OFFSET = "offset";
/** $blogHash */
public static final String PARAM_BLOG = "blog";
/** $blogHash/$entryId */
public static final String PARAM_ENTRY = "entry";
/** tag,tag,tag */
public static final String PARAM_TAG = "tag";
/** $blogHash/$entryId/$attachmentId */
public static final String PARAM_ATTACHMENT = "attachment";
public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("UTF-8");
String attachment = req.getParameter(PARAM_ATTACHMENT);
if (attachment != null) {
// if they requested an attachment, serve it up to 'em
if (renderAttachment(req, resp, attachment))
return;
}
//todo: take care of logo requests, etc
super.service(req, resp);
}
protected void render(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index) throws ServletException, IOException {
Archive archive = BlogManager.instance().getArchive();
Hash blog = null;
String name = req.getParameter(PARAM_BLOG);
if ( (name == null) || (name.trim().length() <= 0) ) {
blog = user.getBlog();
} else {
byte val[] = Base64.decode(name);
if ( (val != null) && (val.length == Hash.HASH_LENGTH) )
blog = new Hash(val);
}
BlogInfo info = null;
if (blog != null)
info = archive.getBlogInfo(blog);
int offset = 0;
String off = req.getParameter(PARAM_OFFSET);
if (off != null) try { offset = Integer.parseInt(off); } catch (NumberFormatException nfe) {}
List posts = getPosts(user, archive, info, req, index);
render(user, req, out, archive, info, posts, offset);
}
private BlogURI getEntry(HttpServletRequest req) {
String param = req.getParameter(PARAM_ENTRY);
if (param != null)
return new BlogURI("blog://" + param);
return null;
}
private List getPosts(User user, Archive archive, BlogInfo info, HttpServletRequest req, ThreadIndex index) {
List rv = new ArrayList(1);
if (info == null) return rv;
ArchiveIndex aindex = archive.getIndex();
BlogURI uri = getEntry(req);
if (uri != null) {
rv.add(uri);
return rv;
}
aindex.selectMatchesOrderByEntryId(rv, info.getKey().calculateHash(), null);
// lets filter out any posts that are not roots
for (int i = 0; i < rv.size(); i++) {
BlogURI curURI = (BlogURI)rv.get(i);
ThreadNode node = index.getNode(curURI);
if ( (node != null) && (node.getParent() == null) ) {
// ok, its a root
Collection tags = node.getTags();
if ( (tags != null) && (tags.contains(BlogInfoData.TAG)) ) {
// skip this, as its an info post
rv.remove(i);
i--;
}
} else {
rv.remove(i);
i--;
}
}
return rv;
}
private void render(User user, HttpServletRequest req, PrintWriter out, Archive archive, BlogInfo info, List posts, int offset) throws IOException {
String title = null;
String desc = null;
BlogInfoData data = null;
if (info != null) {
title = info.getProperty(BlogInfo.NAME);
desc = info.getProperty(BlogInfo.DESCRIPTION);
String dataURI = info.getProperty(BlogInfo.SUMMARY_ENTRY_ID);
if (dataURI != null) {
EntryContainer entry = archive.getEntry(new BlogURI(dataURI));
if (entry != null) {
data = new BlogInfoData();
try {
data.load(entry);
} catch (IOException ioe) {
data = null;
if (_log.shouldLog(Log.WARN))
_log.warn("Error loading the blog info data from " + dataURI, ioe);
}
}
}
}
String pageTitle = "Syndie :: Blogs" + (desc != null ? " :: " + desc : "");
if (title != null) pageTitle = pageTitle + " (" + title + ")";
pageTitle = HTMLRenderer.sanitizeString(pageTitle);
out.write("<html>\n<head>\n<title>" + pageTitle + "</title>\n");
out.write("<style>");
renderStyle(out, info, data, req);
out.write("</style></head>");
renderHeader(user, req, out, info, data, title, desc);
renderReferences(out, info, data);
renderBody(user, out, info, data, posts, offset, archive, req);
out.write("</body></html>\n");
}
private void renderStyle(PrintWriter out, BlogInfo info, BlogInfoData data, HttpServletRequest req) throws IOException {
// modify it based on data.getStyleOverrides()...
out.write(CSS);
Reader css = null;
try {
InputStream in = req.getSession().getServletContext().getResourceAsStream("/syndie.css");
if (in != null) {
css = new InputStreamReader(in, "UTF-8");
char buf[] = new char[1024];
int read = 0;
while ( (read = css.read(buf)) != -1)
out.write(buf, 0, read);
}
} finally {
if (css != null)
css.close();
}
String content = FileUtil.readTextFile("./docs/syndie_standard.css", -1, true);
if (content != null) out.write(content);
}
private void renderHeader(User user, HttpServletRequest req, PrintWriter out, BlogInfo info, BlogInfoData data, String title, String desc) throws IOException {
out.write("<body class=\"syndieBlog\">\n<span style=\"display: none\">" +
"<a href=\"#content\" title=\"Skip to the blog content\">Content</a></span>\n");
renderNavBar(user, req, out);
out.write("<div class=\"syndieBlogHeader\">\n");
if (data != null) {
if (data.isLogoSpecified()) {
out.write("<img src=\"logo.png\" alt=\"\" />\n");
}
}
String name = desc;
if ( (name == null) || (name.trim().length() <= 0) )
name = title;
if ( ( (name == null) || (name.trim().length() <= 0) ) && (info != null) )
name = info.getKey().calculateHash().toBase64();
if (name != null) {
String url = "blog.jsp?" + (info != null ? PARAM_BLOG + "=" + info.getKey().calculateHash().toBase64() : "");
out.write("<b><a href=\"" + url + "\" title=\"Go to the blog root\">"
+ HTMLRenderer.sanitizeString(name) + "</a></b>");
}
out.write("</div>\n");
}
private static final String DEFAULT_GROUP_NAME = "References";
private void renderReferences(PrintWriter out, BlogInfo info, BlogInfoData data) throws IOException {
out.write("<div class=\"syndieBlogLinks\">\n");
if (data != null) {
for (int i = 0; i < data.getReferenceGroupCount(); i++) {
List group = data.getReferenceGroup(i);
if (group.size() <= 0) continue;
PetName pn = (PetName)group.get(0);
String name = null;
if (pn.getGroupCount() <= 0)
name = DEFAULT_GROUP_NAME;
else
name = HTMLRenderer.sanitizeString(pn.getGroup(0));
out.write("<!-- group " + name + " -->\n");
out.write("<div class=\"syndieBlogLinkGroup\">\n");
out.write("<span class=\"syndieBlogLinkGroupName\">" + name + "</span>\n");
out.write("<ul>\n");
for (int j = 0; j < group.size(); j++) {
pn = (PetName)group.get(j);
out.write("<li>" + renderLink(pn) + "</li>\n");
}
out.write("</ul>\n</div>\n<!-- end " + name + " -->\n");
}
}
out.write("<div class=\"syndieBlogLinkGroup\">\n");
out.write("<span class=\"syndieBlogLinkGroupName\">Custom links</span>\n");
out.write("<ul><li><a href=\"\">are not yet implemented</a></li><li><a href=\"\">but are coming soon</a></li></ul>\n");
out.write("</div><!-- end fake group -->");
out.write("<div class=\"syndieBlogMeta\">");
out.write("Secured by <a href=\"http://syndie.i2p.net/\">Syndie</a>");
out.write("</div>\n");
out.write("</div><!-- end syndieBlogLinks -->\n\n");
}
private String renderLink(PetName pn) {
return "<a href=\"\" title=\"go somewhere\">" + HTMLRenderer.sanitizeString(pn.getName()) + "</a>";
}
private static final int POSTS_PER_PAGE = 5;
private void renderBody(User user, PrintWriter out, BlogInfo info, BlogInfoData data, List posts, int offset, Archive archive, HttpServletRequest req) throws IOException {
out.write("<div class=\"syndieBlogBody\">\n<span style=\"display: none\" id=\"content\"></span>\n\n");
if (info == null) {
out.write("No blog specified\n");
return;
}
BlogRenderer renderer = new BlogRenderer(_context, info, data);
if ( (posts.size() == 1) && (req.getParameter(PARAM_ENTRY) != null) ) {
BlogURI uri = (BlogURI)posts.get(0);
EntryContainer entry = archive.getEntry(uri);
renderer.render(user, archive, entry, out, false, true);
renderComments(user, out, info, data, entry, archive, renderer);
} else {
for (int i = offset; i < posts.size() && i < offset + POSTS_PER_PAGE; i++) {
BlogURI uri = (BlogURI)posts.get(i);
EntryContainer entry = archive.getEntry(uri);
renderer.render(user, archive, entry, out, true, true);
}
renderNav(out, info, data, posts, offset, archive, req);
}
out.write("</div><!-- end syndieBlogBody -->\n");
}
private void renderComments(User user, PrintWriter out, BlogInfo info, BlogInfoData data, EntryContainer entry,
Archive archive, BlogRenderer renderer) throws IOException {
ArchiveIndex index = archive.getIndex();
out.write("<div class=\"syndieBlogComments\">\n");
renderComments(user, out, entry.getURI(), archive, index, renderer);
out.write("</div>\n");
}
private void renderComments(User user, PrintWriter out, BlogURI parentURI, Archive archive, ArchiveIndex index, BlogRenderer renderer) throws IOException {
List replies = index.getReplies(parentURI);
if (replies.size() > 0) {
out.write("<ul>\n");
for (int i = 0; i < replies.size(); i++) {
BlogURI uri = (BlogURI)replies.get(i);
out.write("<li>");
if (!shouldIgnore(user, uri)) {
EntryContainer cur = archive.getEntry(uri);
renderer.render(user, archive, cur, out, false, true);
// recurse
renderComments(user, out, uri, archive, index, renderer);
}
out.write("</li>\n");
}
out.write("</ul>\n");
}
}
private boolean shouldIgnore(User user, BlogURI uri) {
PetName pn = user.getPetNameDB().getByLocation(uri.getKeyHash().toBase64());
return ( (pn != null) && pn.isMember(FilteredThreadIndex.GROUP_IGNORE));
}
private void renderNav(PrintWriter out, BlogInfo info, BlogInfoData data, List posts, int offset, Archive archive, HttpServletRequest req) throws IOException {
out.write("<div class=\"syndieBlogNav\"><hr style=\"display: none\" />\n");
String uri = req.getRequestURI() + "?";
if (info != null)
uri = uri + PARAM_BLOG + "=" + info.getKey().calculateHash().toBase64() + "&amp;";
if (offset + POSTS_PER_PAGE >= posts.size())
out.write(POSTS_PER_PAGE + " more older entries");
else
out.write("<a href=\"" + uri + "offset=" + (offset+POSTS_PER_PAGE) + "\">"
+ POSTS_PER_PAGE + " older entries</a>");
out.write(" | ");
if (offset <= 0)
out.write(POSTS_PER_PAGE + " more recent entries");
else
out.write("<a href=\"" + uri + "offset=" +
(offset >= POSTS_PER_PAGE ? offset-POSTS_PER_PAGE : 0)
+ "\">" + POSTS_PER_PAGE + " more recent entries</a>");
out.write("</div><!-- end syndieBlogNav -->\n");
}
/**
* render the attachment to the browser, using the appropriate mime types, etc
* @param attachment formatted as $blogHash/$entryId/$attachmentId
* @return true if rendered
*/
private boolean renderAttachment(HttpServletRequest req, HttpServletResponse resp, String attachment) throws ServletException, IOException {
int split = attachment.lastIndexOf('/');
if (split <= 0)
return false;
BlogURI uri = new BlogURI("blog://" + attachment.substring(0, split));
try {
int attachmentId = Integer.parseInt(attachment.substring(split+1));
if (attachmentId < 0) return false;
EntryContainer entry = BlogManager.instance().getArchive().getEntry(uri);
if (entry == null) {
System.out.println("Could not render the attachment [" + uri + "] / " + attachmentId);
return false;
}
Attachment attachments[] = entry.getAttachments();
if (attachmentId >= attachments.length) {
System.out.println("Out of range attachment on " + uri + ": " + attachmentId);
return false;
}
resp.setContentType(ArchiveViewerBean.getAttachmentContentType(attachments[attachmentId]));
boolean inline = ArchiveViewerBean.getAttachmentShouldShowInline(attachments[attachmentId]);
String filename = ArchiveViewerBean.getAttachmentFilename(attachments[attachmentId]);
if (inline)
resp.setHeader("Content-Disposition", "inline; filename=\"" + filename + "\"");
else
resp.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
int len = ArchiveViewerBean.getAttachmentContentLength(attachments[attachmentId]);
if (len >= 0)
resp.setContentLength(len);
ArchiveViewerBean.renderAttachment(attachments[attachmentId], resp.getOutputStream());
return true;
} catch (NumberFormatException nfe) {}
return false;
}
private static final String CSS =
"<style>\n" +
"body {\n" +
" margin: 0px;\n" +
" padding: 0px;\n" +
" font-family: Arial, Helvetica, sans-serif;\n" +
"}\n" +
".syndieBlog {\n" +
" font-size: 100%;\n" +
" margin: 0px;\n" +
" border: 0px;\n" +
" padding: 0px;\n" +
" border-width: 0px;\n" +
" border-spacing: 0px;\n" +
"}\n" +
".syndieBlogTopNav {\n" +
" width: 100%;\n" +
" height: 20px;\n" +
" background-color: #BBBBBB;\n" +
"}\n" +
".syndieBlogTopNavUser {\n" +
" text-align: left;\n" +
" float: left;\n" +
" display: inline;\n" +
"}\n" +
".syndieBlogTopNavAdmin {\n" +
" text-align: left;\n" +
" float: right;\n" +
" display: inline;\n" +
"}\n" +
".syndieBlogHeader {\n" +
" width: 100%;\n" +
" height: 50px;\n" +
" font-size: 120%;\n" +
" background-color: black;\n" +
" color: white;\n" +
"}\n" +
".syndieBlogLinks {\n" +
" width: 200px;\n" +
"}\n" +
".syndieBlogLinkGroup {\n" +
" text-align: left;\n" +
" font-size: 80%;\n" +
" background-color: #DDD;\n" +
" border: solid;\n" +
" //border-width: 5px 5px 0px 5px;\n" +
" //border-color: #FFFFFF;\n" +
" border-width: 1px 1px 1px 1px;\n" +
" border-color: #000;\n" +
" margin-top: 5px;\n" +
" margin-right: 5px;\n" +
"}\n" +
".syndieBlogLinkGroup ul {\n" +
" list-style: none;\n" +
" margin-left: 0;\n" +
" margin-top: 0;\n" +
" margin-bottom: 0;\n" +
" padding-left: 0;\n" +
"}\n" +
".syndieBlogLinkGroup li {\n" +
" margin: 0;\n" +
"}\n" +
".syndieBlogLinkGroup li a {\n" +
" display: block;\n" +
" width: 100%;\n" +
"}\n" +
".syndieBlogLinkGroupName {\n" +
" font-size: 80%;\n" +
" font-weight: bold;\n" +
"}\n" +
".syndieBlogMeta {\n" +
" text-align: left;\n" +
" font-size: 80%;\n" +
" background-color: #DDD;\n" +
" border: solid;\n" +
" border-width: 1px 1px 1px 1px;\n" +
" border-color: #000;\n" +
" width: 90%;\n" +
" margin-top: 5px;\n" +
" margin-right: 5px;\n" +
"}\n" +
".syndieBlogBody {\n" +
" position: absolute;\n" +
" top: 70px;\n" +
" left: 200px;\n" +
" float: left;\n" +
"}\n" +
".syndieBlogPost {\n" +
" border: solid;\n" +
" border-width: 1px 1px 1px 1px;\n" +
" border-color: #000;\n" +
" margin-top: 5px;\n" +
" width: 100%;\n" +
"}\n" +
".syndieBlogPostHeader {\n" +
" background-color: #BBB;\n" +
"}\n" +
".syndieBlogPostSubject {\n" +
" text-align: left;\n" +
"}\n" +
".syndieBlogPostFrom {\n" +
" text-align: right;\n" +
"}\n" +
".syndieBlogPostSummary {\n" +
" background-color: #FFFFFF;\n" +
"}\n" +
".syndieBlogPostDetails {\n" +
" background-color: #DDD;\n" +
"}\n" +
".syndieBlogNav {\n" +
" text-align: center;\n" +
"}\n" +
".syndieBlogComments {\n" +
" border: none;\n" +
" margin-top: 5px;\n" +
" margin-left: 0px;\n" +
" float: left;\n" +
"}\n" +
".syndieBlogComments ul {\n" +
" list-style: none;\n" +
" margin-left: 10;\n" +
" padding-left: 0;\n" +
"}\n";
protected String getTitle() { return "unused"; }
protected void renderServletDetails(User user, HttpServletRequest req, PrintWriter out, ThreadIndex index,
int threadOffset, BlogURI visibleEntry, Archive archive) throws IOException {
throw new RuntimeException("unused");
}
}

View File

@ -29,8 +29,9 @@ public class ViewBlogsServlet extends BaseServlet {
if ( (lastPost > 0) && (dayBegin - 3*24*60*60*1000l >= lastPost) ) // last post was old 3 days ago
daysAgo = (int)((dayBegin - lastPost + 24*60*60*1000l-1)/(24*60*60*1000l));
daysAgo++;
return getControlTarget() + "?" + ThreadedHTMLRenderer.PARAM_AUTHOR + '=' + blog.toBase64()
+ '&' + ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR + "=true&daysBack=" + daysAgo;
return "blog.jsp?" + ViewBlogServlet.PARAM_BLOG + "=" + blog.toBase64();
//return getControlTarget() + "?" + ThreadedHTMLRenderer.PARAM_AUTHOR + '=' + blog.toBase64()
// + '&' + ThreadedHTMLRenderer.PARAM_THREAD_AUTHOR + "=true&daysBack=" + daysAgo;
}
private String getPostDate(long when) {

View File

@ -69,6 +69,16 @@
<servlet-class>net.i2p.syndie.web.ViewBlogsServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>net.i2p.syndie.web.BlogConfigServlet</servlet-name>
<servlet-class>net.i2p.syndie.web.BlogConfigServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>net.i2p.syndie.web.ViewBlogServlet</servlet-name>
<servlet-class>net.i2p.syndie.web.ViewBlogServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>net.i2p.syndie.UpdaterServlet</servlet-name>
<servlet-class>net.i2p.syndie.UpdaterServlet</servlet-class>
@ -135,6 +145,14 @@
<servlet-name>net.i2p.syndie.web.ViewBlogsServlet</servlet-name>
<url-pattern>/blogs.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>net.i2p.syndie.web.BlogConfigServlet</servlet-name>
<url-pattern>/configblog.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>net.i2p.syndie.web.ViewBlogServlet</servlet-name>
<url-pattern>/blog.jsp</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>

View File

@ -1,4 +1,8 @@
$Id: history.txt,v 1.377 2006/01/01 12:23:29 jrandom Exp $
$Id: history.txt,v 1.378 2006/01/04 21:48:17 jrandom Exp $
2006-01-08 jrandom
* First pass of the new blog interface, though without much of the useful
customization features (coming soon)
2006-01-04 jrandom
* Rather than profile individual tunnels for throughput over their