2005-12-03 jrandom

* Use newgroup-like tags by default in Syndie's interface
This commit is contained in:
jrandom
2005-12-04 03:18:08 +00:00
committed by zzz
parent fef578973a
commit a4cc18df76
6 changed files with 241 additions and 12 deletions

View File

@ -5,7 +5,9 @@ import java.io.IOException;
import java.util.*;
import net.i2p.I2PAppContext;
import net.i2p.client.naming.PetNameDB;
import net.i2p.client.naming.PetName;
import net.i2p.data.*;
import net.i2p.syndie.web.AddressesServlet;
/**
* User session state and preferences.
@ -44,6 +46,14 @@ public class User {
private boolean _dataImported;
static final String PROP_USERHASH = "__userHash";
private static final String DEFAULT_FAVORITE_TAGS[] = {
"syndie", "syndie.tech", "syndie.intro", "syndie.bugs", "syndie.featurerequest", "syndie.announce",
"i2p", "i2p.tech", "i2p.bugs", "i2p.i2phex", "i2p.susimail", "i2p.irc",
"security.misc",
"chat",
"test"
};
/**
* Ugly hack to fetch the default User instance - this is the default
@ -99,6 +109,24 @@ public class User {
public long getMostRecentEntry() { return _mostRecentEntry; }
public Map getBlogGroups() { return _blogGroups; }
public List getShitlistedBlogs() { return _shitlistedBlogs; }
public List getFavoriteTags() {
List rv = new ArrayList();
for (Iterator iter = _petnames.getNames().iterator(); iter.hasNext(); ) {
String name = (String)iter.next();
PetName pn = _petnames.getByName(name);
if (AddressesServlet.PROTO_TAG.equals(pn.getProtocol()))
rv.add(pn.getLocation());
}
if (rv.size() <= 0) {
for (int i = 0; i < DEFAULT_FAVORITE_TAGS.length; i++) {
if (!_petnames.containsName(DEFAULT_FAVORITE_TAGS[i])) {
_petnames.add(new PetName(DEFAULT_FAVORITE_TAGS[i], AddressesServlet.NET_SYNDIE,
AddressesServlet.PROTO_TAG, DEFAULT_FAVORITE_TAGS[i]));
}
}
}
return rv;
}
public String getAddressbookLocation() { return _addressbookLocation; }
public boolean getShowImages() { return _showImagesByDefault; }
public boolean getShowExpanded() { return _showExpandedByDefault; }
@ -282,7 +310,7 @@ public class User {
// shitlist=hash,hash,hash
List shitlistedBlogs = getShitlistedBlogs();
if (shitlistedBlogs.size() > 0) {
buf.setLength(0);
//buf.setLength(0);
buf.append("shitlistedblogs=");
for (int i = 0; i < shitlistedBlogs.size(); i++) {
Hash blog = (Hash)shitlistedBlogs.get(i);
@ -292,6 +320,13 @@ public class User {
}
buf.append('\n');
}
List favoriteTags = getFavoriteTags();
if (favoriteTags.size() > 0) {
buf.append("favoritetags=");
for (int i = 0; i < favoriteTags.size(); i++)
buf.append(((String)favoriteTags.get(i)).trim()).append(" ");
buf.append('\n');
}
return buf.toString();
}

View File

@ -36,6 +36,8 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
public static final String PARAM_REMOVE_FROM_GROUP_NAME = "removeName";
/** group to remove from the bookmarked entry, or if blank, remove the entry itself */
public static final String PARAM_REMOVE_FROM_GROUP = "removeGroup";
/** add the specified tag to the favorites list */
public static final String PARAM_ADD_TAG = "addTag";
/** index into the nav tree to start displaying */
public static final String PARAM_OFFSET = "offset";
public static final String PARAM_TAGS = "tags";
@ -66,6 +68,32 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
return buf.toString();
}
public static String getAddTagToFavoritesLink(String uri, String tag, String author, String visible, String viewPost,
String viewThread, String offset) {
//protected String getAddToGroupLink(User user, Hash author, String group, String uri, String visible,
// String viewPost, String viewThread, String offset, String tags, String filteredAuthor) {
StringBuffer buf = new StringBuffer(64);
buf.append(uri);
buf.append('?');
if (!empty(visible))
buf.append(PARAM_VISIBLE).append('=').append(visible).append('&');
buf.append(PARAM_ADD_TAG).append('=').append(sanitizeTagParam(tag)).append('&');
if (!empty(viewPost))
buf.append(PARAM_VIEW_POST).append('=').append(viewPost).append('&');
else if (!empty(viewThread))
buf.append(PARAM_VIEW_THREAD).append('=').append(viewThread).append('&');
if (!empty(offset))
buf.append(PARAM_OFFSET).append('=').append(offset).append('&');
if (!empty(author))
buf.append(PARAM_AUTHOR).append('=').append(author).append('&');
BaseServlet.addAuthActionParams(buf);
return buf.toString();
}
public static String getNavLink(String uri, String viewPost, String viewThread, String tags, String author, int offset) {
StringBuffer buf = new StringBuffer(64);
buf.append(uri);
@ -213,6 +241,16 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
out.write("'\">");
out.write(" " + tag);
out.write("</a>\n");
if (user.getAuthenticated() && (!user.getFavoriteTags().contains(tag)) && (!"[none]".equals(tag)) ) {
out.write("<a href=\"");
String cur = node.getEntry().getKeyHash().toBase64() + '/' + node.getEntry().getEntryId();
out.write(getAddTagToFavoritesLink(baseURI, tag, filteredAuthor, cur, null, cur, offset));
out.write("\" title=\"Add the tag '");
out.write(tag);
out.write("' to your favorites list\">");
out.write("<img src=\"images/addToFavorites.png\" alt=\":)\" border=\"0\" />");
out.write("</a>\n");
}
}
}
@ -297,7 +335,9 @@ public class ThreadedHTMLRenderer extends HTMLRenderer {
out.write("<tr class=\"postReplyOptions\">\n");
out.write(" <td colspan=\"3\">\n");
out.write(" <input type=\"submit\" value=\"Preview...\" name=\"Post\" />\n");
out.write(" Tags: <input type=\"text\" size=\"10\" name=\"" + PostServlet.PARAM_TAGS + "\" title=\"Optional tags to categorize your response\" />\n");
out.write(" Tags: ");
BaseServlet.writeTagField(_user, "", out, "Optional tags to categorize your response", "No tags", false);
// <input type=\"text\" size=\"10\" name=\"" + PostServlet.PARAM_TAGS + "\" title=\"Optional tags to categorize your response\" />\n");
out.write(" in a new thread? <input type=\"checkbox\" name=\"" + PostServlet.PARAM_IN_NEW_THREAD + "\" value=\"true\" title=\"If true, this will fork a new top level thread\" />\n");
out.write(" refuse replies? <input type=\"checkbox\" name=\"" + PostServlet.PARAM_REFUSE_REPLIES + "\" value=\"true\" title=\"If true, only you will be able to reply to the post\" />\n");
out.write(" attachment: <input type=\"file\" name=\"entryfile0\" />\n");

View File

@ -28,12 +28,14 @@ public class AddressesServlet extends BaseServlet {
public static final String PARAM_NET = "addrNet";
public static final String PARAM_PROTO = "addrProto";
public static final String PARAM_SYNDICATE = "addrSyndicate";
public static final String PARAM_TAG = "addrTag";
public static final String PARAM_ACTION = "action";
public static final String PROTO_BLOG = "syndieblog";
public static final String PROTO_ARCHIVE = "syndiearchive";
public static final String PROTO_I2PHEX = "i2phex";
public static final String PROTO_EEPSITE = "eep";
public static final String PROTO_TAG = "syndietag";
public static final String NET_SYNDIE = "syndie";
public static final String NET_I2P = "i2p";
@ -57,6 +59,10 @@ public class AddressesServlet extends BaseServlet {
public static final String ACTION_UPDATE_EEPSITE = "Update eepsite";
public static final String ACTION_ADD_EEPSITE = "Add eepsite";
public static final String ACTION_DELETE_TAG = "Delete tag";
public static final String ACTION_UPDATE_TAG = "Update tag";
public static final String ACTION_ADD_TAG = "Add tag";
public static final String ACTION_DELETE_OTHER = "Delete address";
public static final String ACTION_UPDATE_OTHER = "Update address";
public static final String ACTION_ADD_OTHER = "Add other address";
@ -75,6 +81,9 @@ public class AddressesServlet extends BaseServlet {
pn = buildNewName(req, PROTO_ARCHIVE);
_log.debug("pn for protoArchive [" + req.getParameter(PARAM_PROTO) + "]: " + pn);
renderArchives(user, db, uri, pn, out);
pn = buildNewName(req, PROTO_TAG);
_log.debug("pn for protoTag [" + req.getParameter(PARAM_TAG) + "]: " + pn);
renderTags(user, db, uri, pn, out);
pn = buildNewName(req, PROTO_I2PHEX);
_log.debug("pn for protoPhex [" + req.getParameter(PARAM_PROTO) + "]: " + pn);
renderI2Phex(user, db, uri, pn, out);
@ -329,6 +338,53 @@ public class AddressesServlet extends BaseServlet {
out.write("<tr><td colspan=\"3\"><hr /></td></tr>\n");
}
private void renderTags(User user, PetNameDB db, String baseURI, PetName newName, PrintWriter out) throws IOException {
TreeSet names = new TreeSet();
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
String name = (String)iter.next();
PetName pn = db.getByName(name);
if (PROTO_TAG.equals(pn.getProtocol()))
names.add(name);
}
out.write("<tr><td colspan=\"3\"><b>Favorite tags</b></td></tr>\n");
for (Iterator iter = names.iterator(); iter.hasNext(); ) {
PetName pn = db.getByName((String)iter.next());
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
writeAuthActionFields(out);
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_TAG + "\" />");
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_SYNDIE + "\" />");
out.write("<tr><td colspan=\"3\">");
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (pn.getIsPublic() ? " checked=\"true\" " : "")
+ " title=\"If checked, this name can be shared with one click when posting\" />\n");
out.write("Name: <input type=\"hidden\" name=\"" + PARAM_NAME + "\" value=\"" + pn.getName()
+ "\" />" + pn.getName() + " ");
out.write("<input type=\"hidden\" name=\"" + PARAM_LOC + "\" value=\"" + pn.getLocation()
+ "\" /> ");
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_DELETE_TAG + "\" /> ");
out.write("</td></tr>\n");
out.write("</form>\n");
}
out.write("<form action=\"" + baseURI + "\" method=\"POST\">");
writeAuthActionFields(out);
out.write("<input type=\"hidden\" name=\"" + PARAM_PROTO + "\" value=\"" + PROTO_TAG + "\" />");
out.write("<input type=\"hidden\" name=\"" + PARAM_NET + "\" value=\"" + NET_SYNDIE + "\" />");
out.write("<tr><td colspan=\"3\">");
out.write("<input type=\"checkbox\" name=\"" + PARAM_IS_PUBLIC + "\" value=\"true\" " + (newName.getIsPublic() ? " checked=\"true\" " : "")
+ " title=\"If checked, this name can be shared with one click when posting\" />\n");
out.write("Name: <input type=\"text\" name=\"" + PARAM_NAME + "\" size=\"10\" value=\"" + newName.getName()
+ "\" title=\"Tag (or group of tags)\" /> ");
out.write("<input type=\"submit\" name=\"" + PARAM_ACTION + "\" value=\"" + ACTION_ADD_TAG + "\" /> ");
out.write("</td></tr>\n");
out.write("</form>\n");
out.write("<tr><td colspan=\"3\"><hr /></td></tr>\n");
}
private void renderOther(User user, PetNameDB db, String baseURI, PetName newName, PrintWriter out) throws IOException {
TreeSet names = new TreeSet();
for (Iterator iter = db.getNames().iterator(); iter.hasNext(); ) {
@ -429,6 +485,7 @@ public class AddressesServlet extends BaseServlet {
if (PROTO_ARCHIVE.equals(reqProto) ||
PROTO_BLOG.equals(reqProto) ||
PROTO_EEPSITE.equals(reqProto) ||
PROTO_TAG.equals(reqProto) ||
PROTO_I2PHEX.equals(reqProto))
return false;
else // its something other than the four default types

View File

@ -64,12 +64,12 @@ public abstract class BaseServlet extends HttpServlet {
* key=value& of params that need to be tacked onto an http request that updates data, to
* prevent spoofing
*/
protected String getAuthActionParams() { return PARAM_AUTH_ACTION + '=' + _authNonce + '&'; }
protected static String getAuthActionParams() { return PARAM_AUTH_ACTION + '=' + _authNonce + '&'; }
/**
* key=value& of params that need to be tacked onto an http request that updates data, to
* prevent spoofing
*/
protected void addAuthActionParams(StringBuffer buf) {
public static void addAuthActionParams(StringBuffer buf) {
buf.append(PARAM_AUTH_ACTION).append('=').append(_authNonce).append('&');
}
@ -139,6 +139,7 @@ public abstract class BaseServlet extends HttpServlet {
forceNewIndex = handleAddressbook(user, req) || forceNewIndex;
forceNewIndex = handleBookmarking(user, req) || forceNewIndex;
forceNewIndex = handleManageTags(user, req) || forceNewIndex;
handleUpdateProfile(user, req);
}
@ -240,6 +241,35 @@ public abstract class BaseServlet extends HttpServlet {
return rv;
}
private boolean handleManageTags(User user, HttpServletRequest req) {
if (!user.getAuthenticated())
return false;
boolean rv = false;
String tag = req.getParameter(ThreadedHTMLRenderer.PARAM_ADD_TAG);
if ( (tag != null) && (tag.trim().length() > 0) ) {
tag = HTMLRenderer.sanitizeString(tag, false);
String name = tag;
PetNameDB db = user.getPetNameDB();
PetName pn = db.getByLocation(tag);
if (pn == null) {
if (db.containsName(name)) {
int i = 0;
while (db.containsName(name + i))
i++;
name = tag + i;
}
pn = new PetName(name, AddressesServlet.NET_SYNDIE, AddressesServlet.PROTO_TAG, tag);
db.add(pn);
BlogManager.instance().saveUser(user);
}
}
return false;
}
private boolean handleAddressbook(User user, HttpServletRequest req) {
if ( (!user.getAuthenticated()) || (empty(AddressesServlet.PARAM_ACTION)) ) {
return false;
@ -247,7 +277,15 @@ public abstract class BaseServlet extends HttpServlet {
String action = req.getParameter(AddressesServlet.PARAM_ACTION);
if ( (AddressesServlet.ACTION_ADD_ARCHIVE.equals(action)) ||
if (AddressesServlet.ACTION_ADD_TAG.equals(action)) {
String name = req.getParameter(AddressesServlet.PARAM_NAME);
if (!user.getPetNameDB().containsName(name)) {
PetName pn = new PetName(name, AddressesServlet.NET_SYNDIE, AddressesServlet.PROTO_TAG, name);
user.getPetNameDB().add(pn);
BlogManager.instance().saveUser(user);
}
return false;
} else if ( (AddressesServlet.ACTION_ADD_ARCHIVE.equals(action)) ||
(AddressesServlet.ACTION_ADD_BLOG.equals(action)) ||
(AddressesServlet.ACTION_ADD_EEPSITE.equals(action)) ||
(AddressesServlet.ACTION_ADD_OTHER.equals(action)) ||
@ -279,6 +317,7 @@ public abstract class BaseServlet extends HttpServlet {
(AddressesServlet.ACTION_DELETE_BLOG.equals(action)) ||
(AddressesServlet.ACTION_DELETE_EEPSITE.equals(action)) ||
(AddressesServlet.ACTION_DELETE_OTHER.equals(action)) ||
(AddressesServlet.ACTION_DELETE_TAG.equals(action)) ||
(AddressesServlet.ACTION_DELETE_PEER.equals(action)) ) {
PetName pn = user.getPetNameDB().getByName(req.getParameter(AddressesServlet.PARAM_NAME));
if (pn != null) {
@ -525,7 +564,7 @@ public abstract class BaseServlet extends HttpServlet {
out.write(user.getUsername());
out.write("</a>\n");
out.write("(<a href=\"switchuser.jsp\" title=\"Log in as another user\">switch</a>)\n");
out.write("<a href=\"" + getPostURI() + "\" title=\"Post a new thread\">Post a new thread</a>\n");
out.write("<a href=\"" + getPostURI() + "\" title=\"Post a new thread\">Post</a>\n");
out.write("<a href=\"addresses.jsp\" title=\"View your addressbook\">Addressbook</a>\n");
} else {
out.write("<form action=\"" + req.getRequestURI() + "\" method=\"POST\">\n");
@ -627,8 +666,8 @@ public abstract class BaseServlet extends HttpServlet {
}
out.write("</select>\n");
out.write("Tags: <input type=\"text\" name=\"" + ThreadedHTMLRenderer.PARAM_TAGS + "\" size=\"10\" value=\"" + tags
+ "\" title=\"Threads are filtered to include only ones with posts containing these tags\" />\n");
out.write("Tags: ");
writeTagField(user, tags, out);
String days = req.getParameter(ThreadedHTMLRenderer.PARAM_DAYS_BACK);
if (days == null)
@ -647,6 +686,52 @@ public abstract class BaseServlet extends HttpServlet {
out.write("</tr>\n");
out.write("</form>\n");
}
protected void writeTagField(User user, String selectedTags, PrintWriter out) throws IOException {
writeTagField(user, selectedTags, out, "Threads are filtered to include only ones with posts containing these tags", "Any tags - no filtering", true);
}
public static void writeTagField(User user, String selectedTags, Writer out, String title, String blankTitle, boolean includeFavoritesTag) throws IOException {
Set favoriteTags = new TreeSet(user.getFavoriteTags());
if (favoriteTags.size() <= 0) {
out.write("<input type=\"text\" name=\"" + ThreadedHTMLRenderer.PARAM_TAGS + "\" size=\"10\" value=\"" + selectedTags
+ "\" title=\"" + title + "\" />\n");
} else {
out.write("<select name=\"" + ThreadedHTMLRenderer.PARAM_TAGS
+ "\" title=\"" + title + "\">");
out.write("<option value=\"\">" + blankTitle + "</option>\n");
if (includeFavoritesTag) {
out.write("<option value=\"");
StringBuffer combinedBuf = new StringBuffer();
for (Iterator iter = favoriteTags.iterator(); iter.hasNext(); ) {
String curFavTag = (String)iter.next();
combinedBuf.append(HTMLRenderer.sanitizeTagParam(curFavTag)).append(" ");
}
String combined = combinedBuf.toString();
if (selectedTags.equals(combined))
out.write(combined + "\" selected=\"true\" >All favorite tags</option>\n");
else
out.write(combined + "\" >All favorite tags</option>\n");
}
boolean matchFound = false;
for (Iterator iter = favoriteTags.iterator(); iter.hasNext(); ) {
String curFavTag = (String)iter.next();
if (selectedTags.equals(curFavTag)) {
out.write("<option value=\"" + HTMLRenderer.sanitizeTagParam(curFavTag) + "\" selected=\"true\" >"
+ HTMLRenderer.sanitizeString(curFavTag) + "</option>\n");
matchFound = true;
} else {
out.write("<option value=\"" + HTMLRenderer.sanitizeTagParam(curFavTag) + "\">"
+ HTMLRenderer.sanitizeString(curFavTag) + "</option>\n");
}
}
if ( (!matchFound) && (selectedTags != null) && (selectedTags.trim().length() > 0) )
out.write("<option value=\"" + HTMLRenderer.sanitizeTagParam(selectedTags)
+ "\" selected=\"true\">" + HTMLRenderer.sanitizeString(selectedTags) + "</option>\n");
out.write("</select>\n");
}
}
protected abstract void renderServletDetails(User user, HttpServletRequest req, PrintWriter out,
ThreadIndex index, int threadOffset, BlogURI visibleEntry,

View File

@ -27,7 +27,7 @@ public class PostServlet extends BaseServlet {
public static final String ACTION_CONFIRM = "confirm";
public static final String PARAM_SUBJECT = "entrysubject";
public static final String PARAM_TAGS = "entrytags";
public static final String PARAM_TAGS = ThreadedHTMLRenderer.PARAM_TAGS;
public static final String PARAM_INCLUDENAMES = "includenames";
public static final String PARAM_TEXT = "entrytext";
public static final String PARAM_HEADERS = "entryheaders";
@ -104,6 +104,8 @@ public class PostServlet extends BaseServlet {
}
}
if (entryTags == null) entryTags = "";
if ( (entryHeaders == null) || (entryHeaders.trim().length() <= 0) )
entryHeaders = ThreadedHTMLRenderer.HEADER_FORCE_NEW_THREAD + ": " + inNewThread + '\n' +
ThreadedHTMLRenderer.HEADER_REFUSE_REPLIES + ": " + refuseReplies;
@ -223,7 +225,10 @@ public class PostServlet extends BaseServlet {
if ( (parentURI != null) && (parentURI.trim().length() > 0) )
out.write("<input type=\"hidden\" name=\"" + PARAM_PARENT + "\" value=\"" + parentURI + "\" />\n");
out.write(" Tags: <input type=\"text\" size=\"10\" name=\"" + PARAM_TAGS + "\" value=\"" + getParam(req, PARAM_TAGS) + "\" title=\"Optional tags to categorize your response\" /><br />\n");
out.write(" Tags: ");
BaseServlet.writeTagField(user, getParam(req, PARAM_TAGS), out, "Optional tags to categorize your post", "No tags", false);
//<input type=\"text\" size=\"10\" name=\"" + PARAM_TAGS + "\" value=\"" + getParam(req, PARAM_TAGS) + "\" title=\"Optional tags to categorize your response\" /><br />\n");
out.write("<br />\n");
boolean inNewThread = getInNewThread(req);
boolean refuseReplies = getRefuseReplies(req);
@ -276,7 +281,11 @@ public class PostServlet extends BaseServlet {
if ( (parentURI != null) && (parentURI.trim().length() > 0) )
out.write("<input type=\"hidden\" name=\"" + PARAM_PARENT + "\" value=\"" + parentURI + "\" />\n");
out.write(" Tags: <input type=\"text\" size=\"10\" name=\"" + PARAM_TAGS + "\" value=\"" + getParam(req, PARAM_TAGS) + "\" /><br />\n");
out.write(" Tags: ");
//<input type=\"text\" size=\"10\" name=\"" + PARAM_TAGS + "\" value=\"" + getParam(req, PARAM_TAGS) + "\" /><br />\n");
out.write(" Tags: ");
BaseServlet.writeTagField(user, getParam(req, PARAM_TAGS), out, "Optional tags to categorize your post", "No tags", false);
out.write("<br />\n");
boolean inNewThread = getInNewThread(req);
boolean refuseReplies = getRefuseReplies(req);

View File

@ -1,4 +1,7 @@
$Id: history.txt,v 1.343 2005/12/03 12:33:35 jrandom Exp $
$Id: history.txt,v 1.344 2005/12/03 14:03:46 jrandom Exp $
2005-12-03 jrandom
* Use newgroup-like tags by default in Syndie's interface
2005-12-03 jrandom
* Added support for a 'most recent posts' view that CofE requested, which