implemented deletion and updating of notes
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
import Login from "./Components/Login.svelte";
|
import Login from "./Components/Login.svelte";
|
||||||
import Messages from "./routes/message/Messages.svelte";
|
import Messages from "./routes/message/Messages.svelte";
|
||||||
import Menu from "./Components/Menu.svelte";
|
import Menu from "./Components/Menu.svelte";
|
||||||
|
import Notes from "./routes/notes/List.svelte";
|
||||||
import ProjectList from "./routes/project/List.svelte";
|
import ProjectList from "./routes/project/List.svelte";
|
||||||
import ProjectAdd from "./routes/project/Create.svelte";
|
import ProjectAdd from "./routes/project/Create.svelte";
|
||||||
import ResetPw from "./routes/user/ResetPw.svelte";
|
import ResetPw from "./routes/user/ResetPw.svelte";
|
||||||
@@ -53,6 +54,7 @@
|
|||||||
<Route path="/document/:id/send" component={SendDoc} />
|
<Route path="/document/:id/send" component={SendDoc} />
|
||||||
<Route path="/document/:id/view" component={ViewDoc} />
|
<Route path="/document/:id/view" component={ViewDoc} />
|
||||||
<Route path="/message/settings" component={Messages} />
|
<Route path="/message/settings" component={Messages} />
|
||||||
|
<Route path="/notes" component={Notes} />
|
||||||
<Route path="/project" component={ProjectList} />
|
<Route path="/project" component={ProjectList} />
|
||||||
<Route path="/project/add" component={ProjectAdd} />
|
<Route path="/project/add" component={ProjectAdd} />
|
||||||
<Route path="/project/:project_id/add_task" component={AddTask} />
|
<Route path="/project/:project_id/add_task" component={AddTask} />
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ async function fetchModules(){
|
|||||||
console.log('error');
|
console.log('error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function go(path){
|
||||||
|
router.navigate(path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
onMount(fetchModules);
|
onMount(fetchModules);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -31,10 +37,11 @@ onMount(fetchModules);
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<nav>
|
<nav>
|
||||||
<a href="" onclick={() => router.navigate('/user')}>{t('users')}</a>
|
<a href="#" onclick={() => go('/user')}>{t('users')}</a>
|
||||||
<a href="" onclick={() => router.navigate('/project')}>{t('projects')}</a>
|
<a href="#" onclick={() => go('/project')}>{t('projects')}</a>
|
||||||
<a href="" onclick={() => router.navigate('/task')}>{t('tasks')}</a>
|
<a href="#" onclick={() => go('/task')}>{t('tasks')}</a>
|
||||||
<a href="" onclick={() => router.navigate('/document')}>{t('documents')}</a>
|
<a href="#" onclick={() => go('/document')}>{t('documents')}</a>
|
||||||
|
<a href="#" onclick={() => go('/notes')}>{t('notes')}</a>
|
||||||
<a href="https://svelte.dev/tutorial/svelte/state" target="_blank">{t('tutorial')}</a>
|
<a href="https://svelte.dev/tutorial/svelte/state" target="_blank">{t('tutorial')}</a>
|
||||||
{#each modules as module,i}<a href={module.url}>{module.name}</a>{/each}
|
{#each modules as module,i}<a href={module.url}>{module.name}</a>{/each}
|
||||||
{#if user.name }
|
{#if user.name }
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
<script>
|
<script>
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { useTinyRouter } from 'svelte-tiny-router';
|
||||||
|
|
||||||
import { api } from '../../urls.svelte.js';
|
import { api } from '../../urls.svelte.js';
|
||||||
import { t } from '../../translations.svelte.js';
|
import { t } from '../../translations.svelte.js';
|
||||||
import { user } from '../../user.svelte.js';
|
import { user } from '../../user.svelte.js';
|
||||||
|
|
||||||
import Editor from '../../Components/MarkdownEditor.svelte';
|
import Editor from '../../Components/MarkdownEditor.svelte';
|
||||||
|
|
||||||
let authors = $state(null);
|
let authors = $state(null);
|
||||||
let error = $state(null);
|
let error = $state(null);
|
||||||
let note = $state({source:null,rendered:null});
|
let note = $state({source:null,rendered:null});
|
||||||
let notes = $state(null);
|
let notes = $state(null);
|
||||||
|
const router = useTinyRouter();
|
||||||
let {
|
let {
|
||||||
module = null,
|
module = null,
|
||||||
entity_id = null
|
entity_id = null
|
||||||
@@ -31,8 +33,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goToEntity(n){
|
||||||
|
router.navigate(`/${n.module}/${n.entity_id}/view`);
|
||||||
|
}
|
||||||
|
|
||||||
async function load(){
|
async function load(){
|
||||||
const url = api(`notes/${module}/${entity_id}`);
|
const url = (module == null && entity_id == null) ? api('notes') : api(`notes/${module}/${entity_id}`);
|
||||||
const resp = await fetch(url,{credentials:'include'});
|
const resp = await fetch(url,{credentials:'include'});
|
||||||
if (resp.ok){
|
if (resp.ok){
|
||||||
const data = await resp.json();
|
const data = await resp.json();
|
||||||
@@ -99,7 +105,11 @@
|
|||||||
{#if notes}
|
{#if notes}
|
||||||
{#each Object.entries(notes) as [nid,note]}
|
{#each Object.entries(notes) as [nid,note]}
|
||||||
<fieldset>
|
<fieldset>
|
||||||
|
{#if module}
|
||||||
<legend class="author">{authors[note.user_id].name}</legend>
|
<legend class="author">{authors[note.user_id].name}</legend>
|
||||||
|
{:else}
|
||||||
|
<legend class="entity" onclick={() => goToEntity(note)}>{t(note.module)} {note.entity_id}</legend>
|
||||||
|
{/if}
|
||||||
<legend class="time">
|
<legend class="time">
|
||||||
{note.timestamp.replace('T',' ')}
|
{note.timestamp.replace('T',' ')}
|
||||||
{#if user.id == note.user_id}
|
{#if user.id == note.user_id}
|
||||||
|
|||||||
@@ -186,7 +186,7 @@
|
|||||||
{#if ready}
|
{#if ready}
|
||||||
<div class="kanban" style="display: grid; grid-template-columns: {`repeat(${columns}, auto)`}">
|
<div class="kanban" style="display: grid; grid-template-columns: {`repeat(${columns}, auto)`}">
|
||||||
<span class="filter">
|
<span class="filter">
|
||||||
<input type="text" bind:value={filter_input} />
|
<input type="text" bind:value={filter_input} autofocus />
|
||||||
{t('filter')}
|
{t('filter')}
|
||||||
</span>
|
</span>
|
||||||
<div class="head">{t('user')}</div>
|
<div class="head">{t('user')}</div>
|
||||||
|
|||||||
@@ -77,10 +77,14 @@ public class NoteModule extends BaseHandler implements NoteService {
|
|||||||
var user = users.refreshSession(ex);
|
var user = users.refreshSession(ex);
|
||||||
if (user.isEmpty()) return unauthorized(ex);
|
if (user.isEmpty()) return unauthorized(ex);
|
||||||
var module = path.pop();
|
var module = path.pop();
|
||||||
if (module == null) throw unprocessable("Module missing in path.");
|
Map<Long,Note> notes = null;
|
||||||
var head = path.pop();
|
if (module == null) {
|
||||||
long entityId = Long.parseLong(head);
|
notes = notesDb.list(user.get().id());
|
||||||
var notes = getNotes(module,entityId);
|
} else {
|
||||||
|
var head = path.pop();
|
||||||
|
long entityId = Long.parseLong(head);
|
||||||
|
notes = getNotes(module, entityId);
|
||||||
|
}
|
||||||
var authors = notes.values().stream().map(Note::authorId).distinct().map(users::loadUser).collect(Collectors.toMap(UmbrellaUser::id,UmbrellaUser::toMap));
|
var authors = notes.values().stream().map(Note::authorId).distinct().map(users::loadUser).collect(Collectors.toMap(UmbrellaUser::id,UmbrellaUser::toMap));
|
||||||
return sendContent(ex, Map.of("notes",mapValues(notes),"authors",authors));
|
return sendContent(ex, Map.of("notes",mapValues(notes),"authors",authors));
|
||||||
} catch (NumberFormatException e){
|
} catch (NumberFormatException e){
|
||||||
@@ -108,6 +112,7 @@ public class NoteModule extends BaseHandler implements NoteService {
|
|||||||
String text = body(ex);
|
String text = body(ex);
|
||||||
if (text.isBlank()) throw missingFieldException("Note text");
|
if (text.isBlank()) throw missingFieldException("Note text");
|
||||||
var note = notesDb.load(noteId);
|
var note = notesDb.load(noteId);
|
||||||
|
if (note.authorId() != user.get().id()) throw forbidden("You are not allowed to edit notes of another user!");
|
||||||
note = new Note(note.id(),note.module(),note.entityId(),note.authorId(),text,LocalDateTime.now());
|
note = new Note(note.id(),note.module(),note.entityId(),note.authorId(),text,LocalDateTime.now());
|
||||||
note = save(note);
|
note = save(note);
|
||||||
return sendContent(ex,note);
|
return sendContent(ex,note);
|
||||||
|
|||||||
@@ -10,6 +10,18 @@ public interface NotesDb {
|
|||||||
|
|
||||||
void deleteEntity(String module, long entityId);
|
void deleteEntity(String module, long entityId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all lists of a person
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Map<Long, Note> list(long authorId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the notes related to a specific entity
|
||||||
|
* @param module
|
||||||
|
* @param entityId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
Map<Long, Note> list(String module, long entityId);
|
Map<Long, Note> list(String module, long entityId);
|
||||||
|
|
||||||
Note load(long noteId);
|
Note load(long noteId);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import de.srsoftware.umbrella.core.model.Note;
|
|||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class SqliteDb implements NotesDb {
|
public class SqliteDb implements NotesDb {
|
||||||
@@ -112,6 +111,22 @@ CREATE TABLE IF NOT EXISTS "{0}" (
|
|||||||
LOG.log(INFO,"Updated task db to version {0}",version);
|
LOG.log(INFO,"Updated task db to version {0}",version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Long, Note> list(long authorId) {
|
||||||
|
try {
|
||||||
|
var notes = new HashMap<Long, Note>();
|
||||||
|
var rs = select(ALL).from(TABLE_NOTES).where(USER_ID,equal(authorId)).exec(db);
|
||||||
|
while (rs.next()) {
|
||||||
|
var note = Note.of(rs);
|
||||||
|
notes.put(note.id(),note);
|
||||||
|
}
|
||||||
|
rs.close();
|
||||||
|
return notes;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
throw new UmbrellaException("Failed to load notes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<Long, Note> list(String module, long entityId) {
|
public Map<Long, Note> list(String module, long entityId) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
"delivery_date": "Lieferdatum",
|
"delivery_date": "Lieferdatum",
|
||||||
"description": "Beschreibung",
|
"description": "Beschreibung",
|
||||||
"display_closed_tasks": "abgeschlossene Aufgaben anzeigen",
|
"display_closed_tasks": "abgeschlossene Aufgaben anzeigen",
|
||||||
"document": "Dokumente",
|
"document": "Dokument",
|
||||||
"document_list": "Dokumente",
|
"document_list": "Dokumente",
|
||||||
"documents": "Dokumente",
|
"documents": "Dokumente",
|
||||||
"do_login" : "anmelden",
|
"do_login" : "anmelden",
|
||||||
|
|||||||
Reference in New Issue
Block a user