diff --git a/frontend/src/routes/wiki/View.svelte b/frontend/src/routes/wiki/View.svelte index 27acdf3..310f2eb 100644 --- a/frontend/src/routes/wiki/View.svelte +++ b/frontend/src/routes/wiki/View.svelte @@ -35,7 +35,19 @@ } async function dropVersion(){ - if (!confirm(t('confirm_delete',{element:t('version_of',{version:page.version,element:page.title})}))) return; + const msg = t('confirm_delete',{element:t('version_of',{version:page.version,element:page.title})}); + if (!confirm(msg)) return; + let url = api(`wiki/page/${key}/version/${page.version}`); + let res = await fetch(url,{ + credentials:'include', + method: 'DELETE' + }); + if (res.ok){ + let json = await res.json(); + router.navigate(`/wiki/${page.id}/view`); + } else { + error = await res.text(); + } } function nonMember(json){ 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 8d9deaf..fdafca7 100644 --- a/wiki/src/main/java/de/srsoftware/umbrella/wiki/SqliteDb.java +++ b/wiki/src/main/java/de/srsoftware/umbrella/wiki/SqliteDb.java @@ -71,21 +71,6 @@ public class SqliteDb extends BaseDb implements WikiDb { 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) { var pages = "CREATE TABLE IF NOT EXISTS {0} ( {1} INT NOT NULL, {2} INT NOT NULL, {3} VARCHAR(255) NOT NULL, {4} TEXT NOT NULL, PRIMARY KEY({1},{2}))"; var users = "CREATE TABLE IF NOT EXISTS {0} ( {1} INT NOT NULL, {2} INT NOT NULL, {3} INT NOT NULL, PRIMARY KEY({1}, {2}))"; @@ -128,6 +113,16 @@ public class SqliteDb extends BaseDb implements WikiDb { } } + @Override + public WikiPage drop(WikiPage page) { + try { + delete().from(TABLE_PAGES).where(ID,equal(page.id())).where(VERSION,equal(page.version())).execute(db); + return page; + } catch (SQLException e) { + throw databaseException("Failed to delete page version!"); + } + } + private void dropOldTables() { try { db.prepareStatement(format("DROP TABLE {0}",TABLE_PAGES)).execute(); @@ -227,6 +222,54 @@ public class SqliteDb extends BaseDb implements WikiDb { } } + @Override + public Map loadMembers(WikiPage page) { + try { + var map = new HashMap(); + var rs = select(ALL).from(TABLE_PAGES_USERS).where(PAGE_ID, equal(page.id())).exec(db); + while (rs.next()){ + var permission = wikiPermission(rs.getInt(PERMISSIONS)); + if (permission != null) map.put(rs.getLong(USER_ID),permission); + } + rs.close(); + return map; + } catch (SQLException e) { + throw databaseException("Failed to load members of \"{0}\" from database!",page.title()); + } + } + + 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); + } + } + + @Override + public WikiPage save(WikiPage page) { + try { + if (page.isDirty(CONTENT) || page.isDirty(ID) || page.isDirty(TITLE)) insertInto(TABLE_PAGES,ID,VERSION,TITLE,CONTENT) + .values(page.id(),page.version(),page.title(),page.content()).execute(db).close(); + if (page.isDirty(MEMBERS)){ + Query.delete().from(TABLE_PAGES_USERS).where(PAGE_ID, 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())); + query.execute(db).close(); + } + return page; + } catch (SQLException e) { + throw databaseException("Failed to write wiki page \"{0}\" to database",page.title(),e); + } + } + private void transferValues(String newTable, String newUsers) { var pageMap = new HashMap(); // map from old IDs to new IDs try { @@ -314,37 +357,4 @@ public class SqliteDb extends BaseDb implements WikiDb { default -> null; }; } - - @Override - public Map loadMembers(WikiPage page) { - try { - var map = new HashMap(); - var rs = select(ALL).from(TABLE_PAGES_USERS).where(PAGE_ID, equal(page.id())).exec(db); - while (rs.next()){ - var permission = wikiPermission(rs.getInt(PERMISSIONS)); - if (permission != null) map.put(rs.getLong(USER_ID),permission); - } - rs.close(); - return map; - } catch (SQLException e) { - 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) || page.isDirty(TITLE)) insertInto(TABLE_PAGES,ID,VERSION,TITLE,CONTENT) - .values(page.id(),page.version(),page.title(),page.content()).execute(db).close(); - if (page.isDirty(MEMBERS)){ - Query.delete().from(TABLE_PAGES_USERS).where(PAGE_ID, 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())); - query.execute(db).close(); - } - return page; - } catch (SQLException 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/WikiDb.java b/wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiDb.java index dfd13b3..64e3aaf 100644 --- a/wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiDb.java +++ b/wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiDb.java @@ -9,6 +9,8 @@ import java.util.Map; public interface WikiDb { + WikiPage drop(WikiPage page); + long getNextId(); boolean isAvailable(String title); 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 a1f6e4d..4d8371d 100644 --- a/wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiModule.java +++ b/wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiModule.java @@ -17,10 +17,8 @@ import de.srsoftware.tools.SessionToken; import de.srsoftware.umbrella.core.BaseHandler; import de.srsoftware.umbrella.core.api.WikiService; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; -import de.srsoftware.umbrella.core.model.Member; -import de.srsoftware.umbrella.core.model.Token; -import de.srsoftware.umbrella.core.model.UmbrellaUser; -import de.srsoftware.umbrella.core.model.WikiPage; +import de.srsoftware.umbrella.core.model.*; + import java.io.IOException; import java.util.Optional; @@ -34,6 +32,35 @@ public class WikiModule extends BaseHandler implements WikiService { } + private boolean deletePage(Path path, UmbrellaUser user, HttpExchange ex) throws IOException { + var id = path.pop(); + if (id == null) return doDelete(path,ex); + Integer version = null; + if (VERSION.equals(path.pop())) version = Integer.parseInt(path.pop()); + if (version == null) throw missingFieldException("VERSION"); + var page = loadMembers(wikiDb.load(id,version)); + var member = page.members().get(user.id()); + if (member == null || member.permission() != EDIT) throw forbidden("You are not allowed to delete \"{0}\"!",page.title()); + return sendContent(ex,wikiDb.drop(page)); + } + + @Override + public boolean doDelete(Path path, HttpExchange ex) throws IOException { + addCors(ex); + try { + Optional token = SessionToken.from(ex).map(Token::of); + var user = userService().loadUser(token); + if (user.isEmpty()) return unauthorized(ex); + var head = path.pop(); + return switch (head) { + case PAGE -> deletePage(path, user.get(), ex); + case null, default -> super.doDelete(path, ex); + }; + } catch (UmbrellaException e){ + return send(ex,e); + } + } + @Override public boolean doGet(Path path, HttpExchange ex) throws IOException { addCors(ex); @@ -64,7 +91,7 @@ public class WikiModule extends BaseHandler implements WikiService { return switch (head) { case null -> getUserPages(user.get(),ex); case PAGE -> patchPage(path, user.get(), ex); - default -> super.doGet(path,ex); + default -> super.doPatch(path,ex); }; } catch (UmbrellaException e){ return send(ex,e);