diff --git a/core/src/main/java/de/srsoftware/umbrella/core/api/NoteService.java b/core/src/main/java/de/srsoftware/umbrella/core/api/NoteService.java index d0abd6d..bd05da2 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/api/NoteService.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/api/NoteService.java @@ -11,4 +11,6 @@ public interface NoteService { Map getNotes(String module, String entityId) throws UmbrellaException; Note save(Note note); + + void updateId(String module, Object oldId, Object newId); } diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/WikiPage.java b/core/src/main/java/de/srsoftware/umbrella/core/model/WikiPage.java index 01e1caf..8e3f217 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/WikiPage.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/WikiPage.java @@ -14,17 +14,19 @@ import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.invalidFi public class WikiPage implements Mappable { - private String id; + private long id; + private String title; private int version; private final List versions = new ArrayList<>(); private final Map members = new HashMap<>(); private String content; private Set dirtyFields = new HashSet<>(); - public WikiPage(String id, int version, String content) { + public WikiPage(long id, String title, int version, String content) { this.id = id; this.version = version; this.content = content; + this.title = title; } public String content(){ @@ -43,14 +45,12 @@ public class WikiPage implements Mappable { return Set.copyOf(dirtyFields); } - public String id(){ + public long id(){ return id; } - private WikiPage id(String newVal) { - if (id.equals(newVal)) return this; + public WikiPage id(long newVal){ id = newVal; - dirtyFields.add(ID); return this; } @@ -63,7 +63,7 @@ public class WikiPage implements Mappable { } public static WikiPage of(ResultSet rs) throws SQLException { - return new WikiPage(rs.getString(ID),rs.getInt(VERSION),rs.getString(CONTENT)); + return new WikiPage(rs.getLong(ID), rs.getString(TITLE),rs.getInt(VERSION),rs.getString(CONTENT)); } public WikiPage patch(JSONObject json, UserService users) { @@ -72,7 +72,7 @@ public class WikiPage implements Mappable { switch (key){ case ID: if (!(val instanceof String s)) throw invalidFieldException(ID,"String"); - id(s); + title(s); break; case CONTENT: if (!(val instanceof String s)) throw invalidFieldException(CONTENT,"String"); @@ -106,6 +106,17 @@ public class WikiPage implements Mappable { return this; } + public String title(){ + return title; + } + + private WikiPage title(String newVal) { + if (title.equals(newVal)) return this; + title = newVal; + dirtyFields.add(TITLE); + return this; + } + @Override public Map toMap() { var memberMap = new HashMap>(); diff --git a/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java b/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java index 0b7fe59..9f760d4 100644 --- a/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java +++ b/notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java @@ -9,11 +9,14 @@ import static de.srsoftware.umbrella.core.ResponseCode.HTTP_UNPROCESSABLE; import static de.srsoftware.umbrella.core.Util.mapValues; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; import static de.srsoftware.umbrella.notes.Constants.CONFIG_DATABASE; +import static de.srsoftware.umbrella.notes.Constants.TABLE_NOTES; import com.sun.net.httpserver.HttpExchange; import de.srsoftware.configuration.Configuration; import de.srsoftware.tools.Path; import de.srsoftware.tools.SessionToken; +import de.srsoftware.tools.jdbc.Condition; +import de.srsoftware.tools.jdbc.Query; import de.srsoftware.umbrella.core.BaseHandler; import de.srsoftware.umbrella.core.ModuleRegistry; import de.srsoftware.umbrella.core.api.NoteService; @@ -180,4 +183,8 @@ public class NoteModule extends BaseHandler implements NoteService { return notesDb.save(note); } + @Override + public void updateId(String module, Object oldId, Object newId) { + notesDb.updateId(module,oldId,newId); + } } diff --git a/notes/src/main/java/de/srsoftware/umbrella/notes/NotesDb.java b/notes/src/main/java/de/srsoftware/umbrella/notes/NotesDb.java index f274006..8ae9911 100644 --- a/notes/src/main/java/de/srsoftware/umbrella/notes/NotesDb.java +++ b/notes/src/main/java/de/srsoftware/umbrella/notes/NotesDb.java @@ -29,4 +29,6 @@ public interface NotesDb { Note load(long noteId); Note save(Note note); + + void updateId(String module, Object oldId, Object newId); } diff --git a/notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java b/notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java index 59e43cf..2f7b44b 100644 --- a/notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java +++ b/notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java @@ -6,6 +6,7 @@ import static de.srsoftware.tools.jdbc.Condition.like; import static de.srsoftware.tools.jdbc.Query.*; import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL; import static de.srsoftware.umbrella.core.Constants.*; +import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseException; import static de.srsoftware.umbrella.notes.Constants.*; import static java.lang.System.Logger.Level.*; import static java.text.MessageFormat.format; @@ -177,7 +178,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( rs.close(); return notes; } catch (SQLException e) { - throw new UmbrellaException("Failed to search notes"); + throw databaseException("Failed to search notes"); } } @@ -194,7 +195,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( rs.close(); return notes; } catch (SQLException e) { - throw new UmbrellaException("Failed to load notes"); + throw databaseException("Failed to load notes"); } } @@ -210,7 +211,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( rs.close(); return notes; } catch (SQLException e) { - throw new UmbrellaException("Failed to load notes"); + throw databaseException("Failed to load notes"); } } @@ -223,7 +224,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( rs.close(); return note; } catch (SQLException e) { - throw new UmbrellaException("Failed to load note {0}",noteId); + throw databaseException("Failed to load note {0}",noteId); } } @@ -247,7 +248,16 @@ CREATE TABLE IF NOT EXISTS "{0}" ( } return note; } catch (SQLException e){ - throw new UmbrellaException("Failed to save note: {0}",note.text()); + throw databaseException("Failed to save note: {0}",note.text()); + } + } + + @Override + public void updateId(String module, Object oldId, Object newId) { + try { + update(TABLE_NOTES).set(ENTITY_ID).where(MODULE,equal(module)).where(ENTITY_ID,equal(oldId)).prepare(db).apply(newId).close(); + } catch (SQLException e) { + throw databaseException("Failed to update {0}.{1} β†’ {0}.{2}",module,oldId,newId); } } } diff --git a/wiki/src/main/java/de/srsoftware/umbrella/wiki/SqliteDb.java b/wiki/src/main/java/de/srsoftware/umbrella/wiki/SqliteDb.java index 4b0a437..1ee95c5 100644 --- a/wiki/src/main/java/de/srsoftware/umbrella/wiki/SqliteDb.java +++ b/wiki/src/main/java/de/srsoftware/umbrella/wiki/SqliteDb.java @@ -3,7 +3,7 @@ package de.srsoftware.umbrella.wiki; import de.srsoftware.tools.jdbc.Condition; import de.srsoftware.tools.jdbc.Query; import de.srsoftware.umbrella.core.BaseDb; -import de.srsoftware.umbrella.core.model.Hash; +import de.srsoftware.umbrella.core.ModuleRegistry; import de.srsoftware.umbrella.core.model.Permission; import de.srsoftware.umbrella.core.model.WikiPage; @@ -25,10 +25,11 @@ import static java.text.MessageFormat.format; public class SqliteDb extends BaseDb implements WikiDb { private static final System.Logger LOG = System.getLogger("TaskDb"); - private static final int INITIAL_DB_VERSION = 1; + private final ModuleRegistry registry; - public SqliteDb(Connection connection) { + public SqliteDb(Connection connection, ModuleRegistry registry) { super(connection); + this.registry = registry; } @Override @@ -63,11 +64,26 @@ public class SqliteDb extends BaseDb implements WikiDb { var newUsers = TABLE_PAGES_USERS+"_new"; createNewTables(newPages, newUsers); transferValues(newPages, newUsers); - //dropOldTables(); - //moveNewTables(); + dropOldTables(); + moveNewTables(newPages, newUsers); } - return setCurrentVersion(1); + return setCurrentVersion(2); + } + + private void moveNewTables(String newPages, String newUsers) { + try { + db.prepareStatement(format("ALTER TABLE {0} RENAME TO {1}",newPages,TABLE_PAGES)).execute(); + } catch (SQLException e) { + LOG.log(ERROR, "Failed to rename table {0} β†’ {1}", newPages, TABLE_PAGES, e); + throw new RuntimeException(e); + } + try { + db.prepareStatement(format("ALTER TABLE {0} RENAME TO {1}",newUsers,TABLE_PAGES_USERS)).execute(); + } catch (SQLException e) { + LOG.log(ERROR, "Failed to rename table {0} β†’ {1}", newUsers, TABLE_PAGES_USERS, e); + throw new RuntimeException(e); + } } private void createNewTables(String newPages, String newUsers) { @@ -112,12 +128,27 @@ public class SqliteDb extends BaseDb implements WikiDb { } } + private void dropOldTables() { + try { + db.prepareStatement(format("DROP TABLE {0}",TABLE_PAGES)).execute(); + } catch (SQLException e) { + LOG.log(ERROR, "Failed to drop table {0}", TABLE_PAGES, e); + throw new RuntimeException(e); + } + try { + db.prepareStatement(format("DROP TABLE {0}",TABLE_PAGES_USERS)).execute(); + } catch (SQLException e) { + LOG.log(ERROR, "Failed to drop table {0}", TABLE_PAGES, e); + throw new RuntimeException(e); + } + } + @Override public List listUserPages(long userId) { try { - var rs = select(ID,"MAX(version) AS version").from(TABLE_PAGES).leftJoin(ID,TABLE_PAGES_USERS,PAGE_ID).where(USER_ID, Condition.equal(userId)).groupBy(ID).sort("ID COLLATE NOCASE ASC").exec(db); + var rs = select(TITLE,"MAX(version) AS version").from(TABLE_PAGES).leftJoin(ID,TABLE_PAGES_USERS,PAGE_ID).where(USER_ID, Condition.equal(userId)).groupBy(TITLE).sort("TITLE COLLATE NOCASE ASC").exec(db); var set = new ArrayList(); - while (rs.next()) set.add(rs.getString(ID)); + while (rs.next()) set.add(rs.getString(TITLE)); rs.close(); return set; } catch (SQLException e) { @@ -126,8 +157,10 @@ public class SqliteDb extends BaseDb implements WikiDb { } @Override - public WikiPage load(String id, Integer version) { - try { + public WikiPage load(String title, Integer version) { + WikiPage page = null; + try { // Try to load by id + long id = Long.parseLong(title); var query = select(ALL).from(TABLE_PAGES).where(ID,Condition.equal(id)); if (version == null) { query.sort(VERSION+" DESC").limit(1); @@ -135,17 +168,35 @@ public class SqliteDb extends BaseDb implements WikiDb { query.where(VERSION,Condition.equal(version)); } var rs = query.exec(db); - WikiPage page = null; if (rs.next()) page = WikiPage.of(rs); rs.close(); - if (page == null) throw notFound("Failed to load wiki page \"{0}\" from database!",id); - rs = select(VERSION).from(TABLE_PAGES).where(ID,Condition.equal(id)).sort(VERSION).exec(db); + } catch (NumberFormatException ignored){ + // title is not an id, go on… + } catch (SQLException e) { + throw databaseException("Failed to load wiki page \"{0}\" from database!",title); + } + if (page == null) try { // page was not loaded by ID + var query = select(ALL).from(TABLE_PAGES).where(TITLE,Condition.equal(title)); + if (version == null) { + query.sort(VERSION+" DESC").limit(1); + } else { + query.where(VERSION,Condition.equal(version)); + } + var rs = query.exec(db); + if (rs.next()) page = WikiPage.of(rs); + rs.close(); + } catch (SQLException e) { + throw databaseException("Failed to load wiki page \"{0}\" from database!",title); + } + if (page == null) throw notFound("Failed to load wiki page \"{0}\" from database!",title); + try { + var rs = select(VERSION).from(TABLE_PAGES).where(ID,Condition.equal(page.id())).sort(VERSION).exec(db); var versions = page.versions(); while (rs.next()) versions.add(rs.getInt(VERSION)); rs.close(); return page; } catch (SQLException e) { - throw databaseException("Failed to load wiki page \"{0}\" from database!",id); + throw databaseException("Failed to load wiki page \"{0}\" from database!",title); } } @@ -191,6 +242,12 @@ public class SqliteDb extends BaseDb implements WikiDb { throw new RuntimeException(e); } + var notes = registry.noteService(); + for (var entry : pageMap.entrySet()){ + var oldId = entry.getKey(); + var newId = entry.getValue(); + notes.updateId("wiki",oldId,newId); + } } private int wikiPermissionCode(Permission perm){ @@ -220,23 +277,23 @@ public class SqliteDb extends BaseDb implements WikiDb { rs.close(); return map; } catch (SQLException e) { - throw databaseException("Failed to load members of \"{0}\" from database!",page.id()); + throw databaseException("Failed to load members of \"{0}\" from database!",page.title()); } } @Override public WikiPage save(WikiPage page) { try { - if (page.isDirty(CONTENT) || page.isDirty(ID)) insertInto(TABLE_PAGES,ID,VERSION,CONTENT).values(page.id(),page.version(),page.content()).execute(db).close(); + if (page.isDirty(CONTENT) || page.isDirty(ID)) insertInto(TABLE_PAGES,ID,VERSION,CONTENT).values(page.title(),page.version(),page.content()).execute(db).close(); if (page.isDirty(MEMBERS)){ - Query.delete().from(TABLE_PAGES_USERS).where(PAGE_ID,Condition.equal(page.id())).where(USER_ID,Condition.notIn(page.members().keySet().toArray())).execute(db); + Query.delete().from(TABLE_PAGES_USERS).where(PAGE_ID,Condition.equal(page.title())).where(USER_ID,Condition.notIn(page.members().keySet().toArray())).execute(db); var query = replaceInto(TABLE_PAGES_USERS,PAGE_ID,USER_ID,PERMISSIONS); - for (var member : page.members().entrySet()) query.values(page.id(),member.getKey(),wikiPermissionCode(member.getValue().permission())); + for (var member : page.members().entrySet()) query.values(page.title(),member.getKey(),wikiPermissionCode(member.getValue().permission())); query.execute(db).close(); } return page; } catch (SQLException e) { - throw databaseException("Failed to write wiki page \"{0}\" to database",page.id(),e); + throw databaseException("Failed to write wiki page \"{0}\" to database",page.title(),e); } } } \ No newline at end of file diff --git a/wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiModule.java b/wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiModule.java index ba68670..9085871 100644 --- a/wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiModule.java +++ b/wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiModule.java @@ -29,7 +29,7 @@ public class WikiModule extends BaseHandler implements WikiService { public WikiModule(ModuleRegistry registry, Configuration config) { super(registry); var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE)); - wikiDb = new SqliteDb(connect(dbFile)); + wikiDb = new SqliteDb(connect(dbFile),registry); }