diff --git a/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkApi.java b/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkApi.java index e3e97d2..931c457 100644 --- a/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkApi.java +++ b/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkApi.java @@ -105,7 +105,7 @@ public class BookmarkApi extends BaseHandler { if (json.has(TAGS) && json.get(TAGS) instanceof JSONArray tagList){ var list = tagList.toList().stream().map(Object::toString).toList(); - tags.save(BOOKMARK,bookmark.id(), userList, list); + tags.save(BOOKMARK,bookmark.urlId(), userList, list); } return sendContent(ex,bookmark); } diff --git a/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/Constants.java b/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/Constants.java index 0ed5343..cb5311a 100644 --- a/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/Constants.java +++ b/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/Constants.java @@ -4,7 +4,7 @@ package de.srsoftware.umbrella.bookmarks; public class Constants { public static final String CONFIG_DATABASE = "umbrella.modules.bookmark.database"; public static final String SHARE = "share"; - public static final String SAVE = "save"; + public static final String TABLE_TOKENS = "tokens"; public static final String TABLE_URLS = "urls"; public static final String TABLE_URL_COMMENTS = "url_comments"; public static final String URL_ID = "url_id"; diff --git a/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/SqliteDb.java b/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/SqliteDb.java index d089631..e28c59a 100644 --- a/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/SqliteDb.java +++ b/bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/SqliteDb.java @@ -75,7 +75,7 @@ CREATE TABLE IF NOT EXISTS {0} ( var rs = select(ALL).from(TABLE_URL_COMMENTS).leftJoin(URL_ID,TABLE_URLS,ID).where(USER_ID, equal(userId)).exec(db); while (rs.next()){ var bookmark = Bookmark.of(rs); - map.put(bookmark.id(),bookmark); + map.put(bookmark.urlId(),bookmark); } rs.close();; return map; @@ -92,7 +92,7 @@ CREATE TABLE IF NOT EXISTS {0} ( if (rs.next()) result = Bookmark.of(rs); rs.close(); if (result != null) return result; - throw UmbrellaException.notFound("No bookmark with id {0}",id); + throw UmbrellaException.notFound("No bookmark with urlId {0}",id); } catch (SQLException e) { throw new UmbrellaException("Failed to load bookmark"); } @@ -102,20 +102,20 @@ CREATE TABLE IF NOT EXISTS {0} ( public Bookmark save(String url, String comment, Collection userIds, LocalDateTime timestamp) { try { var rs = select(ID).from(TABLE_URLS).where(URL, equal(url)).exec(db); - var id = 0L; - if (rs.next()) id = rs.getLong(ID); + var urlId = 0L; + if (rs.next()) urlId = rs.getLong(ID); rs.close(); - if (id == 0) { + if (urlId == 0) { var stmt = insertInto(TABLE_URLS, URL).values(url).execute(db); rs = stmt.getGeneratedKeys(); - if (rs.next()) id = rs.getLong(1); + if (rs.next()) urlId = rs.getLong(1); rs.close(); stmt.close(); } var query = replaceInto(TABLE_URL_COMMENTS,URL_ID,USER_ID,COMMENT, TIMESTAMP); - for (long userId : userIds) query.values(id,userId,comment,timestamp.toEpochSecond(UTC)); + for (long userId : userIds) query.values(urlId,userId,comment,timestamp.toEpochSecond(UTC)); query.execute(db).close(); - return Bookmark.of(id,url,comment,timestamp); + return Bookmark.of(urlId,url,comment,timestamp); } catch (SQLException e) { throw new UmbrellaException("Failed to store url"); } diff --git a/build.gradle.kts b/build.gradle.kts index 5cfa7f8..c3da7a6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -41,7 +41,7 @@ subprojects { testImplementation(platform("org.junit:junit-bom:5.10.0")) testImplementation("org.junit.jupiter:junit-jupiter") implementation("de.srsoftware:configuration.api:1.0.2") - implementation("de.srsoftware:tools.jdbc:1.3.3") + implementation("de.srsoftware:tools.jdbc:2.0.0") implementation("de.srsoftware:tools.http:6.0.4") implementation("de.srsoftware:tools.logging:1.3.2") implementation("de.srsoftware:tools.optionals:1.0.0") diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Bookmark.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Bookmark.java index fdbf210..9ffaf6d 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Bookmark.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Bookmark.java @@ -13,20 +13,20 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Map; -public record Bookmark(long id, String url, String comment, LocalDateTime timestamp, Collection tags) implements Mappable { +public record Bookmark(long urlId, String url, String comment, LocalDateTime timestamp, Collection tags) implements Mappable { public static Bookmark of(ResultSet rs) throws SQLException { return new Bookmark(rs.getLong(ID),rs.getString(URL),rs.getString(COMMENT),LocalDateTime.ofEpochSecond(rs.getLong(TIMESTAMP),0, UTC),new ArrayList<>()); } - public static Bookmark of(long id, String url, String comment, LocalDateTime timestamp){ - return new Bookmark(id,url,comment,timestamp,new ArrayList<>()); + public static Bookmark of(long urlId, String url, String comment, LocalDateTime timestamp){ + return new Bookmark(urlId,url,comment,timestamp,new ArrayList<>()); } @Override public Map toMap() { return Map.of( - ID,id, + ID, urlId, URL, url, COMMENT, Map.of(SOURCE,comment,RENDERED,markdown(comment)), TAGS, tags, diff --git a/tags/src/main/java/de/srsoftware/umbrella/tags/Constants.java b/tags/src/main/java/de/srsoftware/umbrella/tags/Constants.java index e77715a..26a0eff 100644 --- a/tags/src/main/java/de/srsoftware/umbrella/tags/Constants.java +++ b/tags/src/main/java/de/srsoftware/umbrella/tags/Constants.java @@ -8,6 +8,7 @@ public class Constants { public static final String CONFIG_DATABASE = "umbrella.modules.tags.database"; public static final String TABLE_COMMENTS = "comments"; public static final String TABLE_TAGS = "tags"; + public static final String TABLE_TAGS_NEW = "tags_new"; public static final String TAG = "tag"; public static final String URL_HASH = "url_hash"; } diff --git a/tags/src/main/java/de/srsoftware/umbrella/tags/SqliteDb.java b/tags/src/main/java/de/srsoftware/umbrella/tags/SqliteDb.java index f5ff979..04819bd 100644 --- a/tags/src/main/java/de/srsoftware/umbrella/tags/SqliteDb.java +++ b/tags/src/main/java/de/srsoftware/umbrella/tags/SqliteDb.java @@ -6,9 +6,9 @@ import static de.srsoftware.tools.Optionals.isSet; import static de.srsoftware.tools.jdbc.Condition.equal; import static de.srsoftware.tools.jdbc.Condition.isNull; import static de.srsoftware.tools.jdbc.Query.*; +import static de.srsoftware.tools.jdbc.Query.Dialect.SQLITE; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; -import static de.srsoftware.umbrella.bookmarks.Constants.TABLE_URLS; -import static de.srsoftware.umbrella.bookmarks.Constants.TABLE_URL_COMMENTS; +import static de.srsoftware.umbrella.bookmarks.Constants.*; import static de.srsoftware.umbrella.core.Constants.*; import static de.srsoftware.umbrella.core.Constants.ERROR_FAILED_CREATE_TABLE; import static de.srsoftware.umbrella.core.Constants.USER_ID; @@ -24,8 +24,8 @@ import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import java.sql.Connection; import java.sql.SQLException; import java.time.LocalDateTime; -import java.time.ZoneOffset; import java.util.*; +import java.util.regex.Pattern; public class SqliteDb extends BaseDb implements TagDB{ private static final System.Logger LOG = System.getLogger("TagDB"); @@ -49,30 +49,55 @@ public class SqliteDb extends BaseDb implements TagDB{ createLegacyUrlCommentsTable(); createLegacyTagsTable(); case 1: + createNewTagTable(); splitContentToBookmarks(); - createTagTables(); + dropOldTables(); + renameNewTagTable(); } return setCurrentVersion(2); } private void splitContentToBookmarks() { + var pattern = Pattern.compile("/([^/]+)/(\\d+)/view"); try { + var sql = "CREATE TABLE IF NOT EXISTS tags_new (TAG)"; + db.prepareStatement(sql).execute(); // IMPORT BOOKMARKS var commentedURLS = select(ALL).from(TABLE_URLS).leftJoin(HASH,TABLE_URL_COMMENTS,URL_HASH).leftJoin(COMMENT_HASH,TABLE_COMMENTS,HASH).exec(db); + while (commentedURLS.next()){ var userId = commentedURLS.getLong(USER_ID); + var urlHash = commentedURLS.getString(URL_HASH); if (userId == 0) continue; var url = commentedURLS.getString(URL); + LOG.log(DEBUG,url); var timestamp = commentedURLS.getLong(TIMESTAMP); var comment = commentedURLS.getString(COMMENT); if (!isSet(comment)) comment = ""; var dt = is0(timestamp) ? LocalDateTime.now() : LocalDateTime.ofEpochSecond(timestamp,0,UTC); - bookmarks.save(url,comment,List.of(userId),dt.withNano(0)); + var bm = bookmarks.save(url,comment,List.of(userId),dt.withNano(0)); + + String module = null; + long entityId = 0; + var matcher = pattern.matcher(url); + if (matcher.find()){ + module = matcher.group(1); + entityId = Long.parseLong(matcher.group(2)); + LOG.log(DEBUG,"This module is referring to Umbrella`s {0} {1}",module,entityId); + } + + var urlTags = select(ALL).from(TABLE_TAGS).where(URL_HASH,equal(urlHash)).where(USER_ID,equal(userId)).exec(db); + var insertQuery = insertInto(TABLE_TAGS_NEW,TAG,MODULE,ENTITY_ID,USER_ID).ignoreDuplicates(SQLITE); + while (urlTags.next()){ + var tag = urlTags.getString(TAG); + insertQuery.values(tag,BOOKMARK,bm.urlId(),userId); + if (module != null && entityId != 0) insertQuery.values(tag,module,entityId,userId); + } + insertQuery.execute(db).close(); + urlTags.close(); } commentedURLS.close(); - - // UPDATE TAGS } catch (SQLException e) { throw new RuntimeException(e); } @@ -127,9 +152,9 @@ public class SqliteDb extends BaseDb implements TagDB{ } - private void createTagTables() { + private void createNewTagTable() { var createTable = """ -CREATE TABLE IF NOT EXISTS "{0}" ( +CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) NOT NULL, {2} VARCHAR(20) NOT NULL, {3} INTEGER NOT NULL, @@ -137,11 +162,35 @@ CREATE TABLE IF NOT EXISTS "{0}" ( PRIMARY KEY ({1}, {2}, {3}, {4}) )"""; try { - var stmt = db.prepareStatement(format(createTable,TABLE_TAGS, TAG, MODULE, ID, USER_ID)); + var stmt = db.prepareStatement(format(createTable,TABLE_TAGS_NEW, TAG, MODULE, ENTITY_ID, USER_ID)); + stmt.execute(); + stmt.close(); + } catch (SQLException e) { + LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_TAGS_NEW,e); + throw new RuntimeException(e); + } + } + + private void dropOldTables(){ + var sql = "DROP TABLE IF EXISTS {0}"; + for (var table : List.of(TABLE_TAGS,TABLE_COMMENTS,TABLE_TOKENS,TABLE_URL_COMMENTS,TABLE_URLS)) try { + var stmt = db.prepareStatement(format(sql,table)); + stmt.execute(); + stmt.close(); + } catch (SQLException e) { + LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_TAGS_NEW,e); + throw new RuntimeException(e); + } + } + + private void renameNewTagTable() { + var sql = "ALTER TABLE {0} RENAME TO {1}"; + try { + var stmt = db.prepareStatement(format(sql,TABLE_TAGS_NEW, TABLE_TAGS)); stmt.execute(); stmt.close(); } catch (SQLException e) { - LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_TAGS,e); + LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_TAGS_NEW,e); throw new RuntimeException(e); } } @@ -150,10 +199,10 @@ CREATE TABLE IF NOT EXISTS "{0}" ( public String delete(long userId, String module, long entityId, String tag) { try { Query.delete().from(TABLE_TAGS) - .where(TAG,equal(tag)).where(MODULE,equal(module)).where(ID,equal(entityId)).where(USER_ID,equal(userId)) + .where(TAG,equal(tag)).where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId)).where(USER_ID,equal(userId)) .execute(db); Query.delete().from(TABLE_TAGS) - .where(TAG,equal(tag)).where(MODULE,equal(module)).where(ID,equal(entityId)).where(USER_ID,isNull()) + .where(TAG,equal(tag)).where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId)).where(USER_ID,isNull()) .execute(db); return tag; } catch (SQLException e){ @@ -165,7 +214,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( public void deleteEntity(String module, long entityId) { try { Query.delete().from(TABLE_TAGS) - .where(MODULE,equal(module)).where(ID,equal(entityId)) + .where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId)) .execute(db); } catch (SQLException e){ throw new UmbrellaException("Failed to save tags ({0} {1})",module,entityId); @@ -179,14 +228,14 @@ CREATE TABLE IF NOT EXISTS "{0}" ( var result = new HashMap>(); while (rs.next()){ var module = rs.getString(MODULE); - var entityId = rs.getLong(ID); + var entityId = rs.getLong(ENTITY_ID); result.computeIfAbsent(module, k -> new ArrayList<>()).add(entityId); } rs.close(); rs = select(ALL).from(TABLE_TAGS).where(TAG,equal(tag)).where(USER_ID,isNull()).exec(db); while (rs.next()){ var module = rs.getString(MODULE); - var entityId = rs.getLong(ID); + var entityId = rs.getLong(ENTITY_ID); result.computeIfAbsent(module, k -> new ArrayList<>()).add(entityId); } rs.close(); @@ -205,9 +254,9 @@ CREATE TABLE IF NOT EXISTS "{0}" ( public Set list(long userId, String module, long entityId) { try { var tags = new HashSet(); - var rs = select(TAG).from(TABLE_TAGS).where(MODULE,equal(module)).where(ID,equal(entityId)).where(USER_ID,equal(userId)).exec(db); + var rs = select(TAG).from(TABLE_TAGS).where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId)).where(USER_ID,equal(userId)).exec(db); while (rs.next()) tags.add(rs.getString(1)); - rs = select(TAG).from(TABLE_TAGS).where(MODULE,equal(module)).where(ID,equal(entityId)).where(USER_ID,isNull()).exec(db); + rs = select(TAG).from(TABLE_TAGS).where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId)).where(USER_ID,isNull()).exec(db); while (rs.next()) tags.add(rs.getString(1)); rs.close(); return tags; @@ -219,7 +268,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( @Override public void save(Collection userIds, String module, long entityId, Collection tags) { try { - var query = replaceInto(TABLE_TAGS,USER_ID,MODULE,ID,TAG); + var query = replaceInto(TABLE_TAGS,USER_ID,MODULE,ENTITY_ID,TAG); for (var tag : tags) { if (userIds == null) { // tags not assigned to a user are available to all users query.values(null, module, entityId, tag);