From 43586a2ace91edb1d4fa8e86f6fb9bdfa713afbe Mon Sep 17 00:00:00 2001 From: apfelmaennchen Date: Wed, 3 Nov 2010 22:52:03 +0000 Subject: [PATCH] a update to ymarks (please test if you wish): - import HTML (e.g. FF export) via /api/ymarks/import.html - view your import via /api/ymarks/test.html - get a xml list via /api/ymarks/get_ymark_list.xml?tags=&folders= - delete bookmark tables via standard interface /Tables_p.html it is still very experimental!! git-svn-id: https://svn.berlios.de/svnroot/repos/yacy/trunk@7299 6c8d7289-2bf4-0310-a012-ef5d649a1542 --- htroot/api/ymarks/get_ymark_list.java | 91 +++++++++ htroot/api/ymarks/get_ymark_list.xml | 6 + htroot/api/ymarks/get_ymark_tree.java | 176 ++++++++++++++++++ htroot/api/ymarks/get_ymark_tree.json | 9 + htroot/api/ymarks/get_ymark_tree.xml | 11 ++ htroot/api/ymarks/test.html | 38 ++++ htroot/yacy/ui/css/jquery.treeview.css | 15 +- source/de/anomic/data/YMarkIndex.java | 22 ++- source/de/anomic/data/YMarkTables.java | 57 ++++-- source/de/anomic/data/YMarksHTMLImporter.java | 2 +- source/de/anomic/data/YMarksXBELImporter.java | 2 +- 11 files changed, 405 insertions(+), 24 deletions(-) create mode 100644 htroot/api/ymarks/get_ymark_list.java create mode 100644 htroot/api/ymarks/get_ymark_list.xml create mode 100644 htroot/api/ymarks/get_ymark_tree.java create mode 100644 htroot/api/ymarks/get_ymark_tree.json create mode 100644 htroot/api/ymarks/get_ymark_tree.xml create mode 100644 htroot/api/ymarks/test.html diff --git a/htroot/api/ymarks/get_ymark_list.java b/htroot/api/ymarks/get_ymark_list.java new file mode 100644 index 000000000..7b83e0e57 --- /dev/null +++ b/htroot/api/ymarks/get_ymark_list.java @@ -0,0 +1,91 @@ +import java.io.IOException; +import java.util.Iterator; +import java.util.TreeSet; + +import net.yacy.cora.protocol.RequestHeader; +import net.yacy.kelondro.blob.Tables; +import net.yacy.kelondro.index.RowSpaceExceededException; +import net.yacy.kelondro.logging.Log; +import de.anomic.data.YMarkTables; +import de.anomic.data.userDB; +import de.anomic.search.Switchboard; +import de.anomic.server.serverObjects; +import de.anomic.server.serverSwitch; + + +public class get_ymark_list { + + private static Switchboard sb = null; + private static serverObjects prop = null; + + public static serverObjects respond(final RequestHeader header, final serverObjects post, final serverSwitch env) { + sb = (Switchboard) env; + prop = new serverObjects(); + + boolean tags = false; + + final userDB.Entry user = sb.userDB.getUser(header); + final boolean isAdmin = (sb.verifyAuthentication(header, true)); + final boolean isAuthUser = user!= null && user.hasRight(userDB.Entry.BOOKMARK_RIGHT); + final TreeSet bookmarks = new TreeSet(); + + if(isAdmin || isAuthUser) { + final String bmk_user = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN); + + if(post.containsKey(YMarkTables.BOOKMARK.TAGS.key())) { + tags = true; + final String[] tagArray = YMarkTables.cleanTagsString(post.get(YMarkTables.BOOKMARK.TAGS.key())).split(YMarkTables.TAGS_SEPARATOR); + try { + bookmarks.addAll(sb.tables.bookmarks.tags.getBookmarks(bmk_user, tagArray)); + } catch (IOException e) { + Log.logException(e); + } catch (RowSpaceExceededException e) { + Log.logException(e); + } + } + if(post.containsKey(YMarkTables.BOOKMARK.FOLDERS.key())) { + final String[] folderArray = YMarkTables.cleanFoldersString(post.get(YMarkTables.BOOKMARK.FOLDERS.key())).split(YMarkTables.TAGS_SEPARATOR); + try { + if(tags) + bookmarks.retainAll(sb.tables.bookmarks.folders.getBookmarks(bmk_user, folderArray)); + else + bookmarks.addAll(sb.tables.bookmarks.folders.getBookmarks(bmk_user, folderArray)); + } catch (IOException e) { + Log.logException(e); + } catch (RowSpaceExceededException e) { + Log.logException(e); + } + } + putBookmarks(bookmarks, YMarkTables.TABLES.BOOKMARKS.tablename(bmk_user)); + + } else { + prop.put(YMarkTables.USER_AUTHENTICATE,YMarkTables.USER_AUTHENTICATE_MSG); + } + // return rewrite properties + return prop; + } + + private static void putBookmarks(final TreeSet urlSet, final String bmk_table) { + final IteratorurlIter = urlSet.iterator(); + int count = 0; + while(urlIter.hasNext()) { + final byte[] urlHash = urlIter.next().getBytes(); + Tables.Row bmk_row = null; + try { + bmk_row = sb.tables.select(bmk_table, urlHash); + if (bmk_row != null) { + prop.putXML("bookmarks_"+count+"_id", new String(urlHash)); + for (YMarkTables.BOOKMARK bmk : YMarkTables.BOOKMARK.values()) { + prop.putXML("bookmarks_"+count+"_"+bmk.key(), new String(bmk_row.get(bmk.key(),bmk.deflt()))); + } + count++; + } + } catch (IOException e) { + Log.logException(e); + } catch (RowSpaceExceededException e) { + Log.logException(e); + } + } + prop.put("bookmarks", count); + } +} diff --git a/htroot/api/ymarks/get_ymark_list.xml b/htroot/api/ymarks/get_ymark_list.xml new file mode 100644 index 000000000..fbc05ea0b --- /dev/null +++ b/htroot/api/ymarks/get_ymark_list.xml @@ -0,0 +1,6 @@ + + +#{bookmarks}# + +#{/bookmarks}# + \ No newline at end of file diff --git a/htroot/api/ymarks/get_ymark_tree.java b/htroot/api/ymarks/get_ymark_tree.java new file mode 100644 index 000000000..d48f45627 --- /dev/null +++ b/htroot/api/ymarks/get_ymark_tree.java @@ -0,0 +1,176 @@ +import java.io.IOException; +import java.util.Date; +import java.util.Iterator; + +import net.yacy.cora.protocol.RequestHeader; +import net.yacy.kelondro.blob.Tables; +import net.yacy.kelondro.index.RowSpaceExceededException; +import net.yacy.kelondro.logging.Log; +import net.yacy.kelondro.util.DateFormatter; +import de.anomic.data.YMarkTables; +import de.anomic.data.userDB; +import de.anomic.search.Switchboard; +import de.anomic.server.serverObjects; +import de.anomic.server.serverSwitch; + +public class get_ymark_tree { + + public static final String ROOT = "root"; + public static final String SOURCE = "source"; + + // for some reason enums don't work in servlet classes ?!?! + /* + private static final Map TYPE = createMap(); + private static Map createMap() { + Map result = new HashMap(); + result.put("tags", "tag"); + result.put("url", "link"); + result.put("public", "lock"); + result.put("visits", "stat"); + return Collections.unmodifiableMap(result); + } + */ + + static serverObjects prop; + + public static serverObjects respond(final RequestHeader header, final serverObjects post, final serverSwitch env) { + final Switchboard sb = (Switchboard) env; + prop = new serverObjects(); + final userDB.Entry user = sb.userDB.getUser(header); + final boolean isAdmin = (sb.verifyAuthentication(header, true)); + final boolean isAuthUser = user!= null && user.hasRight(userDB.Entry.BOOKMARK_RIGHT); + + if(isAdmin || isAuthUser) { + final String bmk_user = (isAuthUser ? user.getUserName() : YMarkTables.USER_ADMIN); + + + String root = YMarkTables.FOLDERS_ROOT; + String[] foldername = null; + boolean isFolder = true; + + if (post != null){ + if (post.containsKey(ROOT)) { + if (post.get(ROOT).equals(SOURCE) || post.get(ROOT).equals(YMarkTables.FOLDERS_ROOT)) { + root = ""; + } else if (post.get(ROOT).startsWith(YMarkTables.FOLDERS_ROOT)) { + root = post.get(ROOT); + } else { + // root = YMarkTables.FOLDERS_ROOT + post.get(ROOT); + isFolder = false; + } + } + } + + Iterator it = null; + Tables.Row bmk_row = null; + int count = 0; + + if(isFolder) { + // loop through folderList + try { + it = sb.tables.bookmarks.folders.getFolders(bmk_user, root); + } catch (IOException e) { + Log.logException(e); + } + int n = root.split(YMarkTables.FOLDERS_SEPARATOR).length; + if (n == 0) n = 1; + + while (it.hasNext()) { + String folder = it.next(); + foldername = folder.split(YMarkTables.FOLDERS_SEPARATOR); + if (foldername.length == n+1) { + prop.put("folders_"+count+"_foldername", foldername[n]); + prop.put("folders_"+count+"_expanded", "false"); + prop.put("folders_"+count+"_type", "folder"); + prop.put("folders_"+count+"_hash", folder); //TODO: switch from pathString to folderHash + prop.put("folders_"+count+"_url", ""); //TODO: insert folder url + prop.put("folders_"+count+"_hasChildren", "true"); //TODO: determine if folder has children + prop.put("folders_"+count+"_comma", ","); + count++; + } + } + // loop through bookmarkList + try { + it = sb.tables.bookmarks.folders.getBookmarks(bmk_user, root).iterator(); + while (it.hasNext()) { + final String urlHash = new String(it.next()); + bmk_row = sb.tables.select(YMarkTables.TABLES.BOOKMARKS.tablename(bmk_user), urlHash.getBytes()); + if(bmk_row != null) { + final String url = new String(bmk_row.get(YMarkTables.BOOKMARK.URL.key())); + final String title = new String(bmk_row.get(YMarkTables.BOOKMARK.TITLE.key(), YMarkTables.BOOKMARK.TITLE.deflt())); + + // TODO: get rid of bmtype + if (post.containsKey("bmtype")) { + if (post.get("bmtype").equals("title")) { + prop.put("folders_"+count+"_foldername", title); + } else if (post.get("bmtype").equals("href")) { + prop.put("folders_"+count+"_foldername", + ""+title+""); + } + } else { + prop.put("folders_"+count+"_foldername", url); + } + prop.put("folders_"+count+"_expanded", "false"); + prop.put("folders_"+count+"_url", url); + prop.put("folders_"+count+"_type", "file"); + prop.put("folders_"+count+"_hash", urlHash); + prop.put("folders_"+count+"_hasChildren", "true"); + prop.put("folders_"+count+"_comma", ","); + count++; + } + } + count--; + prop.put("folders_"+count+"_comma", ""); + count++; + prop.put("folders", count); + } catch (IOException e) { + Log.logException(e); + } catch (RowSpaceExceededException e) { + Log.logException(e); + } + } else { + try { + bmk_row = sb.tables.select(YMarkTables.TABLES.BOOKMARKS.tablename(bmk_user), post.get(ROOT).getBytes()); + if(bmk_row != null) { + it = bmk_row.keySet().iterator(); + while(it.hasNext()) { + final String key = it.next(); + if(key.startsWith("date")) { + final String date = DateFormatter.formatISO8601(new Date(Long.parseLong(new String(bmk_row.get(key))))); + prop.put("folders_"+count+"_foldername",""+key+": " + date + ""); + putProp(count, "date"); + count++; + } else { + final String value = new String(bmk_row.get(key)); + prop.put("folders_"+count+"_foldername",""+key+": " + value + ""); + if(YMarkTables.BOOKMARK.contains(key)) + putProp(count, YMarkTables.BOOKMARK.get(key).type()); + else + putProp(count, "meta"); + count++; + } + } + count--; + prop.put("folders_"+count+"_comma", ""); + count++; + prop.put("folders", count); + } + } catch (IOException e) { + Log.logException(e); + } catch (RowSpaceExceededException e) { + Log.logException(e); + } + } + } + // return rewrite properties + return prop; + } + public static void putProp(final int count, final String type) { + prop.put("folders_"+count+"_expanded", "false"); + prop.put("folders_"+count+"_url", ""); + prop.put("folders_"+count+"_type", type); + prop.put("folders_"+count+"_hash", ""); + prop.put("folders_"+count+"_hasChildren", "false"); + prop.put("folders_"+count+"_comma", ","); + } +} diff --git a/htroot/api/ymarks/get_ymark_tree.json b/htroot/api/ymarks/get_ymark_tree.json new file mode 100644 index 000000000..7cf91fa05 --- /dev/null +++ b/htroot/api/ymarks/get_ymark_tree.json @@ -0,0 +1,9 @@ +[ +#{folders}#{ +"text": "#[foldername]#", +"expanded": #[expanded]#, +"classes": "#[type]#", +"id": "#[hash]#", +"hasChildren": #[hasChildren]# +}#[comma]##{/folders}# +] \ No newline at end of file diff --git a/htroot/api/ymarks/get_ymark_tree.xml b/htroot/api/ymarks/get_ymark_tree.xml new file mode 100644 index 000000000..3527108b7 --- /dev/null +++ b/htroot/api/ymarks/get_ymark_tree.xml @@ -0,0 +1,11 @@ + + +#{folders}# +#{/folders}# + \ No newline at end of file diff --git a/htroot/api/ymarks/test.html b/htroot/api/ymarks/test.html new file mode 100644 index 000000000..5e4e39747 --- /dev/null +++ b/htroot/api/ymarks/test.html @@ -0,0 +1,38 @@ + + + + + YaCy Bookmarks + + + + + + +

YaCy Bookmarks

+
+
    +
    + + + + + + + + diff --git a/htroot/yacy/ui/css/jquery.treeview.css b/htroot/yacy/ui/css/jquery.treeview.css index 735d92b3b..e5402e5b4 100644 --- a/htroot/yacy/ui/css/jquery.treeview.css +++ b/htroot/yacy/ui/css/jquery.treeview.css @@ -65,4 +65,17 @@ .filetree span.folder, .filetree span.file { padding: 1px 0px 0px 18px; display: block; } .filetree span.folder { background: url(../img/treeview/folder.gif) 0 0 no-repeat; } .filetree li.expandable span.folder { background: url(../img/treeview/folder-closed.gif) 0 0 no-repeat; } -.filetree span.file { background: url(../img/treeview/file.gif) 0 0 no-repeat; } +.filetree span.file { background: url(../img-2/article_text.png) 0 0 no-repeat; } + +.filetree span.meta, +.filetree span.date, +.filetree span.lock, +.filetree span.stat, +.filetree span.link, +.filetree span.tag { padding: 2px 0px 0px 20px; display: block; } +.filetree span.meta { background: url(../img-2/code.png) 0 0 no-repeat; } +.filetree span.date { background: url(../img-2/calendar.png) 0 0 no-repeat; } +.filetree span.lock { background: url(../img-2/lock.png) 0 0 no-repeat; } +.filetree span.stat { background: url(../img-2/bar_graph.png) 0 0 no-repeat; } +.filetree span.link { background: url(../img-2/link.png) 0 0 no-repeat; } +.filetree span.tag { background: url(../img/tags/tag_blue.png) 0 0 no-repeat; } \ No newline at end of file diff --git a/source/de/anomic/data/YMarkIndex.java b/source/de/anomic/data/YMarkIndex.java index 190dde7e2..1a1d5ee5e 100644 --- a/source/de/anomic/data/YMarkIndex.java +++ b/source/de/anomic/data/YMarkIndex.java @@ -40,7 +40,11 @@ public class YMarkIndex { ADD, REMOVE } - + + public final static String PATTERN_PREFIX = "^"; + public final static String PATTERN_POSTFIX = YMarkTables.FOLDERS_SEPARATOR + ".*$"; + public final static String PATTERN_REPLACE = "("+YMarkTables.FOLDERS_SEPARATOR+".[^"+YMarkTables.FOLDERS_SEPARATOR+"]*$)"; + private final WorkTables worktables; private final String table_basename; private final ConcurrentARC cache; @@ -51,24 +55,30 @@ public class YMarkIndex { this.cache = new ConcurrentARC(50,1); } + public String getKeyname(final String user, final byte[] key) throws IOException, RowSpaceExceededException { + final String index_table = user + this.table_basename; + Tables.Row row = this.worktables.select(index_table, key); + return new String(row.get(INDEX.NAME.key(), INDEX.NAME.deflt())); + } + public Iterator getFolders(final String user, final String root) throws IOException { final String index_table = user + this.table_basename; final TreeSet folders = new TreeSet(); - final Pattern r = Pattern.compile("^"+root); + final Pattern r = Pattern.compile(PATTERN_PREFIX + root + PATTERN_POSTFIX); final Iterator it = this.worktables.iterator(index_table, INDEX.NAME.key(), r); - + String path = ""; Row folder; while (it.hasNext()) { - folder = it.next(); + folder = it.next(); path = new String(folder.get(INDEX.NAME.key(), INDEX.NAME.deflt())); while(path.length() > 0 && !path.equals(root)){ folders.add(path); - path = path.replaceAll("(/.[^/]*$)", ""); + path = path.replaceAll(PATTERN_REPLACE, ""); } } - if (!root.equals(YMarkTables.FOLDERS_ROOT)) { folders.add(root); } + if (!root.equals(YMarkTables.FOLDERS_ROOT)) { folders.add(root); } return folders.iterator(); } diff --git a/source/de/anomic/data/YMarkTables.java b/source/de/anomic/data/YMarkTables.java index be64154c9..1e02e86da 100644 --- a/source/de/anomic/data/YMarkTables.java +++ b/source/de/anomic/data/YMarkTables.java @@ -2,9 +2,12 @@ package de.anomic.data; import java.io.IOException; import java.net.MalformedURLException; +import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.Map; + import net.yacy.kelondro.blob.Tables; import net.yacy.kelondro.blob.Tables.Data; import net.yacy.kelondro.data.meta.DigestURI; @@ -49,28 +52,42 @@ public class YMarkTables { } public static enum BOOKMARK { - URL ("url", "", "href", "href"), - TITLE ("title", "", "", ""), - DESC ("desc", "", "", ""), - DATE_ADDED ("date_added", "", "add_date", "added"), - DATE_MODIFIED ("date_modified", "", "last_modified", "modified"), - DATE_VISITED ("date_visited", "", "last_visited", "visited"), - PUBLIC ("public", "flase", "", ""), - TAGS ("tags", "unsorted", "shortcuturl", ""), - VISITS ("visits", "0", "", ""), - FOLDERS ("folders", "/unsorted", "", ""); + URL ("url", "", "href", "href", "link"), + TITLE ("title", "", "", "", "meta"), + DESC ("desc", "", "", "", "comment"), + DATE_ADDED ("date_added", "", "add_date", "added", "date"), + DATE_MODIFIED ("date_modified", "", "last_modified", "modified", "date"), + DATE_VISITED ("date_visited", "", "last_visited", "visited", "date"), + PUBLIC ("public", "flase", "", "", "lock"), + TAGS ("tags", "unsorted", "shortcuturl", "", "tag"), + VISITS ("visits", "0", "", "", "stat"), + FOLDERS ("folders", "/unsorted", "", "", "folder"); private String key; private String dflt; private String html_attrb; private String xbel_attrb; + private String type; + + private static final Map lookup = new HashMap(); + static { + for(BOOKMARK b : EnumSet.allOf(BOOKMARK.class)) + lookup.put(b.key(), b); + } - private BOOKMARK(String k, String s, String a, String x) { + private BOOKMARK(String k, String s, String a, String x, String t) { this.key = k; this.dflt = s; this.html_attrb = a; this.xbel_attrb = x; - } + this.type = t; + } + public static BOOKMARK get(String key) { + return lookup.get(key); + } + public static boolean contains(String key) { + return lookup.containsKey(key); + } public String key() { return this.key; } @@ -83,20 +100,30 @@ public class YMarkTables { public String xbel_attrb() { return this.xbel_attrb; } + public String type() { + return this.type; + } } public final static HashMap POISON = new HashMap(); + public final static String TAGS_SEPARATOR = ","; + public final static String FOLDERS_SEPARATOR = "/"; public final static String FOLDERS_ROOT = "/"; public final static String FOLDERS_UNSORTED = "/unsorted"; - public final static String FOLDERS_IMPORTED = "/imported"; + public final static String FOLDERS_IMPORTED = "/imported"; + public final static String BOOKMARKS_LOG = "BOOKMARKS"; public final static String BOOKMARKS_ID = "id"; - public final static String USER_ADMIN = "admin"; + + public final static String USER_ADMIN = "admin"; public final static String USER_AUTHENTICATE = "AUTHENTICATE"; public final static String USER_AUTHENTICATE_MSG = "Authentication required!"; + + + private WorkTables worktables; public YMarkIndex tags; public YMarkIndex folders; @@ -177,7 +204,7 @@ public class YMarkTables { } return fs.toString(); } - + public void clearIndex(String tablename) { if (tablename.endsWith(TABLES.TAGS.basename())) this.tags.clearCache(); diff --git a/source/de/anomic/data/YMarksHTMLImporter.java b/source/de/anomic/data/YMarksHTMLImporter.java index ef87f38cc..6d90d5790 100644 --- a/source/de/anomic/data/YMarksHTMLImporter.java +++ b/source/de/anomic/data/YMarksHTMLImporter.java @@ -134,7 +134,7 @@ public class YMarksHTMLImporter extends HTMLEditorKit.ParserCallback implements state = STATE.FOLDER_DESC; } else if (t == HTML.Tag.DL) { if(!folder.equals(YMarkTables.FOLDERS_IMPORTED)) { - folder = folder.replaceAll("(/.[^/]*$)", ""); + folder = folder.replaceAll(YMarkIndex.PATTERN_REPLACE, ""); } } else { state = STATE.NOTHING; diff --git a/source/de/anomic/data/YMarksXBELImporter.java b/source/de/anomic/data/YMarksXBELImporter.java index 2611d4bb5..9b7f0a40c 100644 --- a/source/de/anomic/data/YMarksXBELImporter.java +++ b/source/de/anomic/data/YMarksXBELImporter.java @@ -159,7 +159,7 @@ public class YMarksXBELImporter extends DefaultHandler implements Runnable { this.state = STATE.NOTHING; // go up one folder if(!folder.equals(YMarkTables.FOLDERS_IMPORTED)) { - folder = folder.replaceAll("(/.[^/]*$)", ""); + folder = folder.replaceAll(YMarkIndex.PATTERN_REPLACE, ""); this.state = STATE.FOLDER; } } else if (XBEL.INFO.tag().equals(tag)) {