Browse Source

implemented storing edit as new version, impelemented loading of arbitrary versions of wiki page

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
module/wiki
Stephan Richter 2 months ago
parent
commit
aad9a7d9b8
  1. 56
      frontend/src/routes/wiki/View.svelte
  2. 1
      translations/src/main/resources/de.json
  3. 16
      web/src/main/resources/web/css/default.css
  4. 12
      wiki/src/main/java/de/srsoftware/umbrella/wiki/SqliteDb.java
  5. 2
      wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiDb.java
  6. 24
      wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiModule.java

56
frontend/src/routes/wiki/View.svelte

@ -1,25 +1,43 @@ @@ -1,25 +1,43 @@
<script>
import { onMount } from 'svelte';
import { api } from '../../urls.svelte';
import { t } from '../../translations.svelte';
import { onMount } from 'svelte';
import { useTinyRouter } from 'svelte-tiny-router';
import { api } from '../../urls.svelte';
import { t } from '../../translations.svelte';
import Editor from '../../Components/MarkdownEditor.svelte';
import Editor from '../../Components/MarkdownEditor.svelte';
let error = $state(null);
let { id, version } = $props();
let page = $state(null);
let router = useTinyRouter();
async function loadPage(){
const url = api(`wiki/page/${id}`);
const res = await fetch(url,{credentials:'include'});
async function loadContent(res){
if (res.ok){
page = null;
page = await res.json();
page.versions.sort((a,b)=>b-a);
version = page.version;
error = null;
} else {
error = await res.text();
}
}
async function loadPage(){
let path = `wiki/page/${id}`;
if (version) path += `/version/${version}`;
const url = api(path);
const res = await fetch(url,{credentials:'include'});
loadContent(res);
}
function onclick(e){
e.preventDefault();
let href = e.target.getAttribute('href');
if (href) router.navigate(href);
return false;
}
async function patch(data){
const url = api(`wiki/page/${id}`);
const res = await fetch(url,{
@ -27,31 +45,27 @@ @@ -27,31 +45,27 @@
method:'PATCH',
body:JSON.stringify(data)
});
if (res.ok){
error = null;
page = await res.json();
return true;
} else {
error = await res.text();
return false;
}
loadContent(res);
}
onMount(loadPage);
$effect(loadPage);
</script>
<h2>{id}</h2>
{#if error}
<span class="error">{error}</span>
{/if}
{#if page}
<span class="version">{t('version')}</span>
{#each Array.from({ length: page.version }, (_, i) => page.version - i) as v}
{#each page.versions as v}
<span class="version">
{#if v == page.version}[{/if}
<a href={`/wiki/${id}/version/${v}`}>{v}</a>
{#if v == page.version}]{/if}
<a href={`/wiki/${id}/version/${v}`} {onclick} class={page.version == v?'selected':''}>{v}</a>
&nbsp;
</span>
{/each}
{/if}
<h2>{id}</h2>
{#if page}
{#if page.version != page.versions[0]}
<span class="warn">{t('not_recent_version')}</span>
{/if}
<Editor editable={true} value={page.content} onSet={s => patch({content:s})}></Editor>
{/if}

1
translations/src/main/resources/de.json

@ -156,6 +156,7 @@ @@ -156,6 +156,7 @@
"no_company": "keine Firma",
"note": "Notiz",
"notes": "Notizen",
"not_recent_version": "Die ist nicht die neuste Version dieser Seite!",
"number": "Nummer",
"oidc_Login" : "Anmeldung mit OIDC",

16
web/src/main/resources/web/css/default.css

@ -69,6 +69,13 @@ nav { @@ -69,6 +69,13 @@ nav {
border-radius: 6px;
}
.warn {
background: yellow;
color: black;
padding: 5px;
border-radius: 6px;
}
fieldset[tabindex="0"]{
max-height: 55px;
overflow: hidden;
@ -370,3 +377,12 @@ table{ @@ -370,3 +377,12 @@ table{
right: 0;
bottom: 0;
}
.version > a{
padding: 5px;
}
.version a.selected{
border: 1px solid orange;
border-radius: 5px;
}

12
wiki/src/main/java/de/srsoftware/umbrella/wiki/SqliteDb.java

@ -2,8 +2,6 @@ package de.srsoftware.umbrella.wiki; @@ -2,8 +2,6 @@ package de.srsoftware.umbrella.wiki;
import de.srsoftware.tools.jdbc.Condition;
import de.srsoftware.umbrella.core.BaseDb;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Hash;
import de.srsoftware.umbrella.core.model.Permission;
import de.srsoftware.umbrella.core.model.WikiPage;
@ -80,9 +78,15 @@ public class SqliteDb extends BaseDb implements WikiDb { @@ -80,9 +78,15 @@ public class SqliteDb extends BaseDb implements WikiDb {
}
@Override
public WikiPage load(String id) {
public WikiPage load(String id, Integer version) {
try {
var rs = select(ALL).from(TABLE_PAGES).where(ID,Condition.equal(id)).sort(VERSION+" DESC").limit(1).exec(db);
var query = select(ALL).from(TABLE_PAGES).where(ID,Condition.equal(id));
if (version == null) {
query.sort(VERSION+" DESC").limit(1);
} else {
query.where(VERSION,Condition.equal(version));
}
var rs = query.exec(db);
WikiPage page = null;
if (rs.next()) page = WikiPage.of(rs);
rs.close();

2
wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiDb.java

@ -12,7 +12,7 @@ public interface WikiDb { @@ -12,7 +12,7 @@ public interface WikiDb {
List<String> listUserPages(long userId);
WikiPage load(String id);
WikiPage load(String id, Integer version);
Map<Long, Permission> loadMembers(WikiPage page);

24
wiki/src/main/java/de/srsoftware/umbrella/wiki/WikiModule.java

@ -17,11 +17,9 @@ import java.io.IOException; @@ -17,11 +17,9 @@ import java.io.IOException;
import java.util.Optional;
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
import static de.srsoftware.umbrella.core.Constants.VERSION;
import static de.srsoftware.umbrella.core.Paths.PAGE;
import static de.srsoftware.umbrella.core.Paths.VIEW;
import static de.srsoftware.umbrella.core.Util.mapValues;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.forbidden;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
import static de.srsoftware.umbrella.core.model.Permission.EDIT;
import static de.srsoftware.umbrella.wiki.Constants.*;
@ -73,7 +71,17 @@ public class WikiModule extends BaseHandler implements WikiService { @@ -73,7 +71,17 @@ public class WikiModule extends BaseHandler implements WikiService {
private boolean getPage(Path path, UmbrellaUser user, HttpExchange ex) throws IOException {
var id = path.pop();
var page = loadPage(id);
Integer version = null;
if (!path.empty()){
var head = path.pop();
if (!VERSION.equals(head)) return doGet(path,ex);
try {
version = Integer.parseInt(path.pop());
} catch (NumberFormatException e) {
throw invalidFieldException(VERSION,"int number");
}
}
var page = loadPage(id,version);
var permission = page.members().get(user.id());
if (permission == null) throw forbidden("You are not allowed to access \"{0}\"!",id);
return sendContent(ex, page);
@ -97,14 +105,14 @@ public class WikiModule extends BaseHandler implements WikiService { @@ -97,14 +105,14 @@ public class WikiModule extends BaseHandler implements WikiService {
return page;
}
private WikiPage loadPage(String id){
private WikiPage loadPage(String id, Integer version){
if (id == null) throw missingFieldException(PAGE_ID);
return loadMembers(wikiDb.load(id));
return loadMembers(wikiDb.load(id, version));
}
private boolean patchPage(Path path, UmbrellaUser user, HttpExchange ex) throws IOException {
var id = path.pop();
var page = loadPage(id);
var page = loadPage(id, null);
var member = page.members().get(user.id());
if (member == null || member.permission() != EDIT) throw forbidden("You are not allowed to edit {0}!",id);
var json = json(ex);

Loading…
Cancel
Save