diff --git a/htroot/api/ymarks/add_ymark.java b/htroot/api/ymarks/add_ymark.java index 03b01af6e..67b04002b 100644 --- a/htroot/api/ymarks/add_ymark.java +++ b/htroot/api/ymarks/add_ymark.java @@ -1,7 +1,8 @@ import java.io.IOException; import java.net.MalformedURLException; import java.util.Date; - +import java.util.HashSet; +import java.util.Iterator; import net.yacy.cora.protocol.RequestHeader; import net.yacy.kelondro.blob.Tables; import net.yacy.kelondro.blob.Tables.Data; @@ -17,8 +18,10 @@ import de.anomic.server.serverSwitch; public class add_ymark { + private static Switchboard sb = null; + public static serverObjects respond(final RequestHeader header, final serverObjects post, final serverSwitch env) { - final Switchboard sb = (Switchboard) env; + sb = (Switchboard) env; final serverObjects prop = new serverObjects(); final userDB.Entry user = sb.userDB.getUser(header); @@ -26,20 +29,28 @@ public class add_ymark { final boolean isAuthUser = user!= null && user.hasRight(userDB.Entry.BOOKMARK_RIGHT); if(isAdmin || isAuthUser) { - final String table = (isAuthUser ? user.getUserName() : "admin")+"_"+YMarkStatics.TABLE_BOOKMARKS_BASENAME; - - byte[] pk = null; - try { - pk = YMarkStatics.getBookmarkID(post.get(YMarkStatics.TABLE_BOOKMARKS_COL_URL,"")); - } catch (MalformedURLException e) { - Log.logException(e); + final String bmk_table = (isAuthUser ? user.getUserName() : "admin")+"_"+YMarkStatics.TABLE_BOOKMARKS_BASENAME; + final String tag_table = (isAuthUser ? user.getUserName() : "admin")+"_"+YMarkStatics.TABLE_TAGS_BASENAME; + + byte[] urlHash = null; + if(post.containsKey(YMarkStatics.TABLE_BOOKMARKS_COL_URL)) { + try { + urlHash = YMarkStatics.getBookmarkId(post.get(YMarkStatics.TABLE_BOOKMARKS_COL_URL,"")); + } catch (MalformedURLException e) { + Log.logException(e); + } + } else if (post.containsKey(YMarkStatics.TABLE_BOOKMARKS_COL_ID)) { + urlHash = post.get(YMarkStatics.TABLE_BOOKMARKS_COL_ID).getBytes(); + } + if(urlHash == null) { + prop.put("result", "0"); + return prop; } - assert pk != null; // read old entry from the bookmarks table (if exists) - Tables.Row row = null; + Tables.Row bmk_row = null; try { - row = sb.tables.select(table, pk); + bmk_row = sb.tables.select(bmk_table, urlHash); } catch (IOException e) { Log.logException(e); } catch (RowSpaceExceededException e) { @@ -48,38 +59,65 @@ public class add_ymark { // insert or update entry try { - if (row == null) { + if (bmk_row == null) { // create and insert new entry Data data = new Data(); + final String tagsString = YMarkStatics.cleanTagsString(post.get(YMarkStatics.TABLE_BOOKMARKS_COL_TAGS,"")); + final byte[] date = DateFormatter.formatShortMilliSecond(new Date()).getBytes(); + data.put(YMarkStatics.TABLE_BOOKMARKS_COL_URL, post.get(YMarkStatics.TABLE_BOOKMARKS_COL_URL,"").getBytes()); data.put(YMarkStatics.TABLE_BOOKMARKS_COL_TITLE, post.get(YMarkStatics.TABLE_BOOKMARKS_COL_TITLE,"").getBytes()); data.put(YMarkStatics.TABLE_BOOKMARKS_COL_DESC, post.get(YMarkStatics.TABLE_BOOKMARKS_COL_DESC,"").getBytes()); data.put(YMarkStatics.TABLE_BOOKMARKS_COL_PUBLIC, post.get(YMarkStatics.TABLE_BOOKMARKS_COL_PUBLIC,"false").getBytes()); - data.put(YMarkStatics.TABLE_BOOKMARKS_COL_TAGS, YMarkStatics.cleanTagsString(post.get(YMarkStatics.TABLE_BOOKMARKS_COL_TAGS,"")).getBytes()); - - byte[] date = DateFormatter.formatShortMilliSecond(new Date()).getBytes(); + data.put(YMarkStatics.TABLE_BOOKMARKS_COL_TAGS, tagsString.getBytes()); data.put(YMarkStatics.TABLE_BOOKMARKS_COL_DATE_ADDED, date); data.put(YMarkStatics.TABLE_BOOKMARKS_COL_DATE_MODIFIED, date); data.put(YMarkStatics.TABLE_BOOKMARKS_COL_DATE_VISITED, date); + sb.tables.insert(bmk_table, urlHash, data); + + + final String[] tagArray = tagsString.split(","); + for (final String tag : tagArray) { + updateTagTable(tag_table, tag, new String(urlHash), YMarkStatics.TABLE_TAGS_ACTION_ADD); + } - sb.tables.insert(table, pk, data); - } else { - // modify and update existing entry - row.put(YMarkStatics.TABLE_BOOKMARKS_COL_TITLE, post.get(YMarkStatics.TABLE_BOOKMARKS_COL_TITLE,row.get(YMarkStatics.TABLE_BOOKMARKS_COL_TITLE,"")).getBytes()); - row.put(YMarkStatics.TABLE_BOOKMARKS_COL_DESC, post.get(YMarkStatics.TABLE_BOOKMARKS_COL_DESC,row.get(YMarkStatics.TABLE_BOOKMARKS_COL_DESC,"")).getBytes()); - row.put(YMarkStatics.TABLE_BOOKMARKS_COL_PUBLIC, post.get(YMarkStatics.TABLE_BOOKMARKS_COL_PUBLIC,row.get(YMarkStatics.TABLE_BOOKMARKS_COL_PUBLIC,"false")).getBytes()); - row.put(YMarkStatics.TABLE_BOOKMARKS_COL_TAGS, YMarkStatics.cleanTagsString(post.get(YMarkStatics.TABLE_BOOKMARKS_COL_TAGS,row.get(YMarkStatics.TABLE_BOOKMARKS_COL_TAGS,""))).getBytes()); + + } else { + // modify and update existing entry + bmk_row.put(YMarkStatics.TABLE_BOOKMARKS_COL_TITLE, post.get(YMarkStatics.TABLE_BOOKMARKS_COL_TITLE,bmk_row.get(YMarkStatics.TABLE_BOOKMARKS_COL_TITLE,"")).getBytes()); + bmk_row.put(YMarkStatics.TABLE_BOOKMARKS_COL_DESC, post.get(YMarkStatics.TABLE_BOOKMARKS_COL_DESC,bmk_row.get(YMarkStatics.TABLE_BOOKMARKS_COL_DESC,"")).getBytes()); + bmk_row.put(YMarkStatics.TABLE_BOOKMARKS_COL_PUBLIC, post.get(YMarkStatics.TABLE_BOOKMARKS_COL_PUBLIC,bmk_row.get(YMarkStatics.TABLE_BOOKMARKS_COL_PUBLIC,"false")).getBytes()); + + final String tagsString = YMarkStatics.cleanTagsString(post.get(YMarkStatics.TABLE_BOOKMARKS_COL_TAGS,"")); + HashSetold_tagSet = YMarkStatics.getTagSet(bmk_row.get(YMarkStatics.TABLE_BOOKMARKS_COL_TAGS,""), false); + HashSetnew_tagSet = YMarkStatics.getTagSet(tagsString, false); + bmk_row.put(YMarkStatics.TABLE_BOOKMARKS_COL_TAGS, tagsString.getBytes()); // modify date attribute - row.put(YMarkStatics.TABLE_BOOKMARKS_COL_DATE_MODIFIED, DateFormatter.formatShortMilliSecond(new Date()).getBytes()); + bmk_row.put(YMarkStatics.TABLE_BOOKMARKS_COL_DATE_MODIFIED, DateFormatter.formatShortMilliSecond(new Date()).getBytes()); + + // update bmk_table + sb.tables.update(bmk_table, bmk_row); + + //update tag_table + Iterator tagIter; + + new_tagSet.removeAll(old_tagSet); + tagIter = new_tagSet.iterator(); + while(tagIter.hasNext()) { + updateTagTable(tag_table, tagIter.next(), new String(urlHash), YMarkStatics.TABLE_TAGS_ACTION_ADD); + } - sb.tables.update(table, row); - assert pk != null; + new_tagSet = YMarkStatics.getTagSet(tagsString, false); + old_tagSet.removeAll(new_tagSet); + tagIter=old_tagSet.iterator(); + while(tagIter.hasNext()) { + updateTagTable(tag_table, tagIter.next(), new String(urlHash), YMarkStatics.TABLE_TAGS_ACTION_REMOVE); + } } } catch (IOException e) { Log.logException(e); } - Log.logInfo(YMarkStatics.TABLE_BOOKMARKS_LOG, "insertBookmark: "+post.get(YMarkStatics.TABLE_BOOKMARKS_COL_URL,"")); prop.put("result", "1"); } else { prop.put("AUTHENTICATE","Authentication required!"); @@ -87,4 +125,55 @@ public class add_ymark { // return rewrite properties return prop; } + + private static boolean updateTagTable(final String tag_table, final String tag, final String urlHash, final int action) { + Tables.Row tag_row = null; + final byte[] tagHash = YMarkStatics.getTagHash(tag); + HashSeturlSet = new HashSet(); + try { + tag_row = sb.tables.select(tag_table, tagHash); + if(tag_row == null) { + switch (action) { + case YMarkStatics.TABLE_TAGS_ACTION_ADD: + urlSet.add(urlHash); + break; + default: + return false; + } + Data tagEntry = new Data(); + tagEntry.put(YMarkStatics.TABLE_TAGS_COL_TAG, tag.getBytes()); + tagEntry.put(YMarkStatics.TABLE_TAGS_COL_URLS, YMarkStatics.keySetToBytes(urlSet)); + sb.tables.insert(tag_table, tagHash, tagEntry); + return true; + } else { + urlSet = YMarkStatics.keysStringToKeySet(new String(tag_row.get(YMarkStatics.TABLE_TAGS_COL_URLS))); + if(urlSet.contains(urlHash)) + Log.logInfo(YMarkStatics.TABLE_BOOKMARKS_LOG, "ok, urlHash found!"); + switch (action) { + case YMarkStatics.TABLE_TAGS_ACTION_ADD: + urlSet.add(urlHash); + break; + case YMarkStatics.TABLE_TAGS_ACTION_REMOVE: + urlSet.remove(urlHash); + if(urlSet.isEmpty()) { + sb.tables.delete(tag_table, tagHash); + return true; + } + break; + default: + return false; + } + tag_row.put(YMarkStatics.TABLE_TAGS_COL_URLS, YMarkStatics.keySetToBytes(urlSet)); + sb.tables.update(tag_table, tag_row); + return true; + } + } catch (IOException e) { + Log.logException(e); + } catch (RowSpaceExceededException e) { + Log.logException(e); + } + return false; + } + + } diff --git a/htroot/api/ymarks/delete_ymark.java b/htroot/api/ymarks/delete_ymark.java index b3694d4c4..fb887ea1a 100644 --- a/htroot/api/ymarks/delete_ymark.java +++ b/htroot/api/ymarks/delete_ymark.java @@ -20,14 +20,16 @@ public class delete_ymark { final boolean isAuthUser = user!= null && user.hasRight(userDB.Entry.BOOKMARK_RIGHT); if(isAdmin || isAuthUser) { - final String table = (isAuthUser ? user.getUserName() : "admin")+"_"+YMarkStatics.TABLE_BOOKMARKS_BASENAME; + final String bmk_table = (isAuthUser ? user.getUserName() : "admin")+"_"+YMarkStatics.TABLE_BOOKMARKS_BASENAME; + final String tag_table = (isAuthUser ? user.getUserName() : "admin")+"_"+YMarkStatics.TABLE_TAGS_BASENAME; + byte[] pk = null; if(post.containsKey(YMarkStatics.TABLE_BOOKMARKS_COL_ID)) { pk = post.get(YMarkStatics.TABLE_BOOKMARKS_COL_ID).getBytes(); } else if(post.containsKey(YMarkStatics.TABLE_BOOKMARKS_COL_URL)) { try { - pk = YMarkStatics.getBookmarkID(post.get(YMarkStatics.TABLE_BOOKMARKS_COL_URL)); + pk = YMarkStatics.getBookmarkId(post.get(YMarkStatics.TABLE_BOOKMARKS_COL_URL)); } catch (MalformedURLException e) { Log.logException(e); } @@ -37,7 +39,7 @@ public class delete_ymark { } assert pk != null; try { - sb.tables.delete(table,pk); + sb.tables.delete(bmk_table,pk); prop.put("result", "1"); } catch (IOException e) { Log.logException(e); diff --git a/htroot/api/ymarks/get_ymark.java b/htroot/api/ymarks/get_ymark.java new file mode 100644 index 000000000..c03380ead --- /dev/null +++ b/htroot/api/ymarks/get_ymark.java @@ -0,0 +1,64 @@ +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +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.YMarkStatics; +import de.anomic.data.userDB; +import de.anomic.search.Switchboard; +import de.anomic.server.serverObjects; +import de.anomic.server.serverSwitch; + + +public class get_ymark { + public static serverObjects respond(final RequestHeader header, final serverObjects post, final serverSwitch env) { + final Switchboard sb = (Switchboard) env; + final serverObjects 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); + + final String bmk_table = (isAuthUser ? user.getUserName() : "admin")+"_"+YMarkStatics.TABLE_BOOKMARKS_BASENAME; + final String tag_table = (isAuthUser ? user.getUserName() : "admin")+"_"+YMarkStatics.TABLE_TAGS_BASENAME; + + if(post.containsKey(YMarkStatics.TABLE_TAGS_COL_TAG)) { + final byte[] tagHash = YMarkStatics.getTagHash(post.get(YMarkStatics.TABLE_TAGS_COL_TAG)); + Tables.Row tag_row = null; + try { + tag_row = sb.tables.select(tag_table, tagHash); + if (tag_row != null) { + final IteratorurlIter = (YMarkStatics.keysStringToKeySet(new String(tag_row.get(YMarkStatics.TABLE_TAGS_COL_URLS)))).iterator(); + int count = 0; + while(urlIter.hasNext()) { + final byte[] urlHash = urlIter.next().getBytes(); + Tables.Row bmk_row = null; + bmk_row = sb.tables.select(bmk_table, urlHash); + if (bmk_row != null) { + prop.putXML("bookmarks_"+count+"_link", new String(bmk_row.get(YMarkStatics.TABLE_BOOKMARKS_COL_URL,""))); + prop.putXML("bookmarks_"+count+"_hash", new String(urlHash)); + prop.putXML("bookmarks_"+count+"_tags", new String(bmk_row.get(YMarkStatics.TABLE_BOOKMARKS_COL_TAGS,""))); + count++; + } + } + prop.put("bookmarks", count); + } + else { + prop.put("result", "0"); + return prop; + } + } catch (IOException e) { + Log.logException(e); + } catch (RowSpaceExceededException e) { + Log.logException(e); + } + } + // return rewrite properties + return prop; + } +} diff --git a/htroot/api/ymarks/get_ymark.xml b/htroot/api/ymarks/get_ymark.xml new file mode 100644 index 000000000..17317d3d2 --- /dev/null +++ b/htroot/api/ymarks/get_ymark.xml @@ -0,0 +1,6 @@ + + +#{bookmarks}# + +#{/bookmarks}# + \ No newline at end of file diff --git a/source/de/anomic/data/YMarkStatics.java b/source/de/anomic/data/YMarkStatics.java index 9bba101d2..99c4aa422 100644 --- a/source/de/anomic/data/YMarkStatics.java +++ b/source/de/anomic/data/YMarkStatics.java @@ -2,6 +2,7 @@ package de.anomic.data; import java.net.MalformedURLException; import java.util.HashSet; +import java.util.Iterator; import java.util.Set; import net.yacy.kelondro.data.meta.DigestURI; @@ -10,22 +11,27 @@ import net.yacy.kelondro.data.word.Word; public class YMarkStatics { public final static String TABLE_BOOKMARKS_BASENAME = "bookmarks"; - public final static String TABLE_BOOKMARKS_LOG = "BOOKMARKS"; public final static String TABLE_BOOKMARKS_COL_ID = "id"; public final static String TABLE_BOOKMARKS_COL_URL = "url"; public final static String TABLE_BOOKMARKS_COL_TITLE = "title"; public final static String TABLE_BOOKMARKS_COL_DESC = "desc"; - public final static String TABLE_BOOKMARKS_COL_DATE_ADDED = "added"; public final static String TABLE_BOOKMARKS_COL_DATE_MODIFIED = "modified"; public final static String TABLE_BOOKMARKS_COL_DATE_VISITED = "visited"; - public final static String TABLE_BOOKMARKS_COL_PUBLIC = "public"; public final static String TABLE_BOOKMARKS_COL_TAGS = "tags"; - public final static byte[] getBookmarkID(String url) throws MalformedURLException { + public final static String TABLE_TAGS_BASENAME = "tags"; + public final static String TABLE_TAGS_COL_ID = "id"; + public final static String TABLE_TAGS_COL_TAG = "tag"; + public final static String TABLE_TAGS_COL_URLS = "urls"; + + public final static int TABLE_TAGS_ACTION_ADD = 1; + public final static int TABLE_TAGS_ACTION_REMOVE = 2; + + public final static byte[] getBookmarkId(String url) throws MalformedURLException { if (!url.toLowerCase().startsWith("http://") && !url.toLowerCase().startsWith("https://")) { url="http://"+url; } @@ -36,24 +42,50 @@ public class YMarkStatics { return Word.word2hash(tag.toLowerCase()); } - public final static Set getTagSet(final String tagsString) { - SettagSet = new HashSet(); - String[] tagArray = cleanTagsString(tagsString).split(","); + public final static HashSet getTagSet(final String tagsString, boolean clean) { + HashSettagSet = new HashSet(); + final String[] tagArray = clean ? cleanTagsString(tagsString).split(",") : tagsString.split(","); for (final String tag : tagArray) { tagSet.add(tag); } return tagSet; } - public final static Set getTagHashSet(final String tagsString) { - SettagSet = new HashSet(); - String[] tagArray = cleanTagsString(tagsString).split(","); + public final static HashSet getTagSet(final String tagsString) { + return getTagSet(tagsString, true); + } + + public final static HashSet getTagIdSet(final String tagsString, boolean clean) { + HashSettagSet = new HashSet(); + final String[] tagArray = clean ? cleanTagsString(tagsString).split(",") : tagsString.split(","); for (final String tag : tagArray) { tagSet.add(getTagHash(tag)); } return tagSet; } + public final static Set getTagIdSet(final String tagsString) { + return getTagIdSet(tagsString, true); + } + + public final static byte[] keySetToBytes(final HashSet urlSet) { + final Iterator urlIter = urlSet.iterator(); + String urls = ""; + while(urlIter.hasNext()) { + urls = urls + "," + urlIter.next(); + } + return cleanTagsString(urls).getBytes(); + } + + public final static HashSet keysStringToKeySet(final String keysString) { + HashSet keySet = new HashSet(); + final String[] keyArray = keysString.split(","); + for (final String key : keyArray) { + keySet.add(key); + } + return keySet; + } + public final static String cleanTagsString(String tagsString) { // get rid of heading, trailing and double commas since they are useless while (tagsString.length() > 0 && tagsString.charAt(0) == ',') {