Browse Source

implemented /bookmark/<ID>/view

featue/module_registry
Stephan Richter 3 months ago
parent
commit
783eaf3303
  1. 15
      bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkApi.java
  2. 6
      bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkDb.java
  3. 22
      bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/SqliteDb.java
  4. 3
      core/src/main/java/de/srsoftware/umbrella/core/model/Bookmark.java
  5. 2
      frontend/src/App.svelte
  6. 12
      frontend/src/routes/bookmark/Index.svelte
  7. 18
      frontend/src/routes/bookmark/Template.svelte
  8. 32
      frontend/src/routes/bookmark/View.svelte

15
bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkApi.java

@ -19,11 +19,10 @@ import de.srsoftware.umbrella.core.api.UserService; @@ -19,11 +19,10 @@ import de.srsoftware.umbrella.core.api.UserService;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Token;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import org.json.JSONArray;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import org.json.JSONArray;
public class BookmarkApi extends BaseHandler {
private final BookmarkDb db;
@ -47,7 +46,11 @@ public class BookmarkApi extends BaseHandler { @@ -47,7 +46,11 @@ public class BookmarkApi extends BaseHandler {
var head = path.pop();
return switch (head) {
case LIST -> getUserBookmarks(user.get(),ex);
case null, default -> super.doPost(path,ex);
case null -> super.doPost(path,ex);
default -> {
var id = Long.parseLong(head);
yield getBookmark(user.get(),id,ex);
}
};
} catch (NumberFormatException e){
return sendContent(ex,HTTP_BAD_REQUEST,"Invalid project id");
@ -56,6 +59,12 @@ public class BookmarkApi extends BaseHandler { @@ -56,6 +59,12 @@ public class BookmarkApi extends BaseHandler {
}
}
private boolean getBookmark(UmbrellaUser user, long id, HttpExchange ex) throws IOException {
var bookmark = db.load(id,user.id());
tags.getTags(BOOKMARK, id, user).forEach(bookmark.tags()::add);
return sendContent(ex,bookmark);
}
@Override
public boolean doPost(Path path, HttpExchange ex) throws IOException {
addCors(ex);

6
bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/BookmarkDb.java

@ -5,7 +5,9 @@ import de.srsoftware.umbrella.core.model.Bookmark; @@ -5,7 +5,9 @@ import de.srsoftware.umbrella.core.model.Bookmark;
import java.util.Map;
public interface BookmarkDb {
Bookmark save(String url, String comment, long userId);
Map<Long, Bookmark> list(long userId);
Bookmark load(long id, long userId);
Map<Long, Bookmark> list(long id);
Bookmark save(String url, String comment, long userId);
}

22
bookmark/src/main/java/de/srsoftware/umbrella/bookmarks/SqliteDb.java

@ -1,22 +1,20 @@ @@ -1,22 +1,20 @@
/* © SRSoftware 2025 */
package de.srsoftware.umbrella.bookmarks;
import static de.srsoftware.tools.jdbc.Condition.equal;
import static de.srsoftware.tools.jdbc.Query.*;
import static de.srsoftware.tools.jdbc.Query.SelectQuery.ALL;
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.Util.sha1;
import static java.lang.System.Logger.Level.ERROR;
import static java.text.MessageFormat.format;
import static java.time.ZoneOffset.UTC;
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.Bookmark;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.time.LocalDateTime;
import java.util.HashMap;
@ -73,7 +71,7 @@ CREATE TABLE IF NOT EXISTS {0} ( @@ -73,7 +71,7 @@ CREATE TABLE IF NOT EXISTS {0} (
public Map<Long, Bookmark> list(long userId) {
try {
var map = new HashMap<Long,Bookmark>();
var rs = select(ALL).from(TABLE_URL_COMMENTS).leftJoin(URL_ID,TABLE_URLS,ID).where(USER_ID, Condition.equal(userId)).exec(db);
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);
@ -85,11 +83,25 @@ CREATE TABLE IF NOT EXISTS {0} ( @@ -85,11 +83,25 @@ CREATE TABLE IF NOT EXISTS {0} (
}
}
@Override
public Bookmark load(long id, long userId) {
try {
Bookmark result = null;
var rs = select(ALL).from(TABLE_URLS).leftJoin(ID,TABLE_URL_COMMENTS,URL_ID).where(ID,equal(id)).where(USER_ID,equal(userId)).exec(db);
if (rs.next()) result = Bookmark.of(rs);
rs.close();
if (result != null) return result;
throw UmbrellaException.notFound("No bookmark with id {0}",id);
} catch (SQLException e) {
throw new UmbrellaException("Failed to load bookmark");
}
}
@Override
public Bookmark save(String url, String comment, long userId) {
try {
var timestamp = LocalDateTime.now();
var rs = select(ID).from(TABLE_URLS).where(URL,Condition.equal(url)).exec(db);
var rs = select(ID).from(TABLE_URLS).where(URL, equal(url)).exec(db);
var id = 0L;
if (rs.next()) id = rs.getLong(ID);
rs.close();

3
core/src/main/java/de/srsoftware/umbrella/core/model/Bookmark.java

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
package de.srsoftware.umbrella.core.model;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Util.markdown;
import static java.time.ZoneOffset.UTC;
import de.srsoftware.tools.Mappable;
@ -27,7 +28,7 @@ public record Bookmark(long id, String url, String comment, LocalDateTime timest @@ -27,7 +28,7 @@ public record Bookmark(long id, String url, String comment, LocalDateTime timest
return Map.of(
ID,id,
URL, url,
COMMENT, comment,
COMMENT, Map.of(SOURCE,comment,RENDERED,markdown(comment)),
TAGS, tags,
TIMESTAMP, timestamp.withNano(0)
);

2
frontend/src/App.svelte

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
import AddDoc from "./routes/document/Add.svelte";
import AddTask from "./routes/task/Add.svelte";
import Bookmark from "./routes/bookmark/View.svelte";
import Bookmarks from "./routes/bookmark/Index.svelte";
import Callback from "./routes/user/OidcCallback.svelte";
import DocList from "./routes/document/List.svelte";
@ -52,6 +53,7 @@ @@ -52,6 +53,7 @@
<Menu />
<Route path="/" component={User} />
<Route path="/bookmark" component={Bookmarks} />
<Route path="/bookmark/:id/view" component={Bookmark} />
<Route path="/document" component={DocList} />
<Route path="/document/add" component={AddDoc} />
<Route path="/document/:id/send" component={SendDoc} />

12
frontend/src/routes/bookmark/Index.svelte

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
import Editor from '../../Components/MarkdownEditor.svelte';
import Tags from '../tags/TagList.svelte';
import Template from './Template.svelte';
let bookmarks = $state(null);
let new_bookmark = $state({
@ -75,16 +76,7 @@ @@ -75,16 +76,7 @@
<button {onclick}>{t('save')}</button>
{#if bookmarks}
{#each bookmarks as bookmark}
<fieldset class="bookmark">
<legend>
<a href={bookmark.url} target="_blank" class="url">{bookmark.url}</a>
</legend>
<legend class="date">
{bookmark.timestamp.replace('T',' ')}
</legend>
{bookmark.comment}
<Tags module="bookmark" id={bookmark.id} />
</fieldset>
<Template {bookmark} />
{/each}
{/if}
</fieldset>

18
frontend/src/routes/bookmark/Template.svelte

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
<script>
import Tags from '../tags/TagList.svelte';
let { bookmark } = $props();
</script>
{#if bookmark}
<fieldset class="bookmark">
<legend>
<a href={bookmark.url} target="_blank" class="url">{bookmark.url}</a>
</legend>
<legend class="date">
{bookmark.timestamp.replace('T',' ')}
</legend>
{@html bookmark.comment.rendered}
<Tags module="bookmark" id={bookmark.id} />
</fieldset>
{/if}

32
frontend/src/routes/bookmark/View.svelte

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
<script>
import { onMount } from 'svelte';
import Bookmark from './Template.svelte';
import { api } from '../../urls.svelte.js';
import { t } from '../../translations.svelte.js';
import Editor from '../../Components/MarkdownEditor.svelte';
import Template from './Template.svelte';
let bookmark = $state(null);
let error = $state(null);
let { id } = $props();
async function load(){
const url = api(`bookmark/${id}`);
const resp = await fetch(url,{credentials:'include'});
if (resp.ok){
bookmark = await resp.json();
} else {
error = await resp.text();
}
}
onMount(load);
</script>
{#if error}
<span class="error">{error}</span>
{/if}
<Template {bookmark} />
Loading…
Cancel
Save