From 7b259e7425bf0e49ed750282b3fd29533093ed23 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Wed, 22 Oct 2025 18:51:14 +0200 Subject: [PATCH 1/4] preparing moving of locations --- .../umbrella/core/model/DbLocation.java | 5 +++ frontend/src/routes/stock/Index.svelte | 33 ++++++++++++++----- frontend/src/routes/stock/Locations.svelte | 14 ++++++-- .../srsoftware/umbrella/stock/Constants.java | 1 + .../srsoftware/umbrella/stock/SqliteDb.java | 2 +- .../de/srsoftware/umbrella/stock/StockDb.java | 2 +- .../umbrella/stock/StockModule.java | 23 +++++++++++-- 7 files changed, 65 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java b/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java index 040f25e..d92ca00 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java @@ -43,6 +43,11 @@ public class DbLocation extends Location { return parentLocationId; } + public DbLocation parent(DbLocation newParent) { + parentLocationId = newParent.id(); + return this; + } + @Override public DbLocation resolve() { return this; diff --git a/frontend/src/routes/stock/Index.svelte b/frontend/src/routes/stock/Index.svelte index 6eb70ad..2eac356 100644 --- a/frontend/src/routes/stock/Index.svelte +++ b/frontend/src/routes/stock/Index.svelte @@ -10,10 +10,11 @@ import Notes from '../notes/RelatedNotes.svelte'; import Tags from '../tags/TagList.svelte'; - let loc_data = $derived.by(loadLocation); - let item = $state(null); - let location = $state(null); - let draggedItem = $state(null) + let loc_data = $derived.by(loadLocation); + let item = $state(null); + let location = $state(null); + let draggedItem = $state(null) + let draggedLocation = $state(null) $effect(() => { // This effect runs whenever `location` changes @@ -37,6 +38,16 @@ } else error(res); } + function drag_item(item){ + draggedLocation = null; + draggedItem = item; + } + + function drag_location(loc){ + draggedItem = null; + draggedLocation = loc; + } + function dropNestedLocation(locations,loc){ for (let [idx,entry] of locations.entries()){ if (entry.id == loc.id){ @@ -49,8 +60,9 @@ } async function move_dragged_to(new_loc){ - const data = { item : draggedItem.id, target: new_loc.id }; - const url = api('stock/move_item'); + console.log({move_dragged_to:JSON.parse(JSON.stringify(new_loc))}); + const data = draggedItem ? { item : draggedItem.id, target: new_loc.id } : { location : draggedLocation.id, target: new_loc.id } + const url = api(draggedItem ? 'stock/move_item' : 'stock/move_location'); const res = await fetch(url,{ credentials : 'include', method : 'PATCH', @@ -118,7 +130,12 @@ {#each top_level as realm,idx}

{realm.name}

{#if realm.locations} - + {/if} {/each} {/if} @@ -130,7 +147,7 @@ {#if location}

{location.name}

{/if} - a.code.localeCompare(b.code))} bind:selected={item} drag_start={item => draggedItem = item} /> + a.code.localeCompare(b.code))} bind:selected={item} drag_start={drag_item} />
diff --git a/frontend/src/routes/stock/Locations.svelte b/frontend/src/routes/stock/Locations.svelte index 3dea134..93e2f21 100644 --- a/frontend/src/routes/stock/Locations.svelte +++ b/frontend/src/routes/stock/Locations.svelte @@ -5,7 +5,13 @@ import LineEditor from '../../Components/LineEditor.svelte'; - let { locations, move_dragged_to = new_loc => {}, parent = null, selected = $bindable(null) } = $props(); + let { + drag_start = loc => console.log({dragging:loc}), + locations, + move_dragged_to = new_loc => {}, + parent = null, + selected = $bindable(null) + } = $props(); let show_location_form = $state(false); let new_location_name = $state(null); @@ -102,12 +108,14 @@ {#each locations as location}
  • toggleChildren(e, location)} class="{location.locations?'expanded':'collapsed'} {location.highlight?'highlight':null}" + draggable={true} ondragover={e => drag_over(e,location)} ondrop={e => onDrop(e,location)} - ondragleave={e => delete location.highlight}> + ondragleave={e => delete location.highlight} + ondragstart={e => drag_start(location)} > {location.name} {#if location.locations} - + {/if}
  • {/each} diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/Constants.java b/stock/src/main/java/de/srsoftware/umbrella/stock/Constants.java index c56347b..4445dcb 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/Constants.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/Constants.java @@ -13,6 +13,7 @@ public class Constants { public static final String ITEMS = "items"; public static final String LOCATIONS = "locations"; public static final String MOVE_ITEM = "move_item"; + public static final String MOVE_LOCATION = "move_location"; public static final String OF_USER = "of_user"; public static final String PARENT = "parent"; public static final String PROPERTY_ID = "prop_id"; diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java index c904b84..a75ad0d 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java @@ -288,7 +288,7 @@ public class SqliteDb extends BaseDb implements StockDb { } @Override - public Location save(DbLocation location) { + public DbLocation save(DbLocation location) { if (location.id() == 0) { // new location try { var rs = insertInto(TABLE_LOCATIONS,OWNER,PARENT_LOCATION_ID,NAME,DESCRIPTION) diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java b/stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java index 80a954b..e0904a3 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/StockDb.java @@ -15,7 +15,7 @@ public interface StockDb { Collection listUserLocations(UmbrellaUser userId); Item loadItem(long id); DbLocation loadLocation(long locationId); - Location save(DbLocation location); + DbLocation save(DbLocation location); Item save(Item item); Property setProperty(long itemId, long existingPropId, Object value); } diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java index a1205c8..597b3ac 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java @@ -113,7 +113,8 @@ public class StockModule extends BaseHandler implements StockService { var user = userService().loadUser(token); if (user.isEmpty()) return unauthorized(ex); return switch (path.pop()){ - case MOVE_ITEM -> patchMove(user.get(), path,ex); + case MOVE_ITEM -> patchMoveItem(user.get(), path,ex); + case MOVE_LOCATION -> patchMoveLocation(user.get(), path, ex); case null -> patchItem(user.get(),ex); default -> super.doPatch(path,ex); }; @@ -213,7 +214,7 @@ public class StockModule extends BaseHandler implements StockService { return sendContent(ex,stockDb.save(item)); } - private boolean patchMove(UmbrellaUser user, Path path, HttpExchange ex) throws IOException { + private boolean patchMoveItem(UmbrellaUser user, Path path, HttpExchange ex) throws IOException { var json = json(ex); if (!(json.get(ITEM) instanceof Number itemId)) throw missingFieldException(ITEM); if (!(json.get(TARGET) instanceof Number locationId)) throw missingFieldException(TARGET); @@ -232,6 +233,24 @@ public class StockModule extends BaseHandler implements StockService { return sendContent(ex,item); } + private boolean patchMoveLocation(UmbrellaUser user, Path path, HttpExchange ex) throws IOException { + var json = json(ex); + if (!(json.get(LOCATION) instanceof Number locationId)) throw missingFieldException(LOCATION); + if (!(json.get(TARGET) instanceof Number destLocationId)) throw missingFieldException(TARGET); + var location = stockDb.loadLocation(locationId.longValue()); + + var owner = location.owner().resolve(); + if (!assigned(owner,user)) throw forbidden("You are not allowed to alter the location of \"{0}\"!",location.name()); + + var target = stockDb.loadLocation(locationId.longValue()); + var locOwner = target.resolve().owner().resolve(); + if (!assigned(locOwner,user)) throw forbidden("You are not allowed to modify \"{0}\"!",target.name()); + + if (!locOwner.equals(owner)) throw unprocessable("You may not move locations from one owner ({0}) to another ({1})",owner,locOwner); + location = stockDb.save(location.parent(target)); + return sendContent(ex,location); + } + private boolean postLocation(UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); if (!(json.get(NAME) instanceof String name)) throw missingFieldException(NAME); From eafa7a5b5fc5e81eef2e540890b9ddf19e83a52a Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Wed, 22 Oct 2025 21:16:25 +0200 Subject: [PATCH 2/4] implemented moving of locations Signed-off-by: Stephan Richter --- .../umbrella/core/model/DbLocation.java | 17 +++++++++++++++++ frontend/src/routes/stock/Index.svelte | 10 ++++++++-- .../de/srsoftware/umbrella/stock/SqliteDb.java | 14 ++++++++++++-- .../srsoftware/umbrella/stock/StockModule.java | 2 +- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java b/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java index d92ca00..87e9b58 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java @@ -6,7 +6,9 @@ import static de.srsoftware.umbrella.core.Constants.*; import de.srsoftware.umbrella.core.api.Owner; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.HashSet; import java.util.Map; +import java.util.Set; public class DbLocation extends Location { private Owner owner; @@ -14,6 +16,7 @@ public class DbLocation extends Location { private String name; private String description; private String relation; // when added to an item, this field describes the type of the relation + private Set dirtyFields = new HashSet<>(); public DbLocation(long id, Owner owner, Long parentLocationId, String name, String description){ super(id); @@ -23,10 +26,23 @@ public class DbLocation extends Location { this.description = description; } + public DbLocation clear(){ + dirtyFields.clear(); + return this; + } + public String description() { return description; } + public boolean isDirty() { + return !dirtyFields.isEmpty(); + } + + public boolean isDirty(String field){ + return dirtyFields.contains(field); + } + public String name() { return name; } @@ -45,6 +61,7 @@ public class DbLocation extends Location { public DbLocation parent(DbLocation newParent) { parentLocationId = newParent.id(); + dirtyFields.add(PARENT_LOCATION_ID); return this; } diff --git a/frontend/src/routes/stock/Index.svelte b/frontend/src/routes/stock/Index.svelte index 2eac356..2be4886 100644 --- a/frontend/src/routes/stock/Index.svelte +++ b/frontend/src/routes/stock/Index.svelte @@ -60,7 +60,6 @@ } async function move_dragged_to(new_loc){ - console.log({move_dragged_to:JSON.parse(JSON.stringify(new_loc))}); const data = draggedItem ? { item : draggedItem.id, target: new_loc.id } : { location : draggedLocation.id, target: new_loc.id } const url = api(draggedItem ? 'stock/move_item' : 'stock/move_location'); const res = await fetch(url,{ @@ -70,7 +69,14 @@ }); if (res.ok){ yikes(); - location = new_loc; + location = new_loc; + if (!draggedItem){ + for (var owner of top_level){ + if (owner.locations && dropNestedLocation(owner.locations,draggedLocation)) break; + } + } + draggedItem = null; + draggedLocation = null; } else { error(res); } diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java index a75ad0d..0207854 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java @@ -292,7 +292,7 @@ public class SqliteDb extends BaseDb implements StockDb { if (location.id() == 0) { // new location try { var rs = insertInto(TABLE_LOCATIONS,OWNER,PARENT_LOCATION_ID,NAME,DESCRIPTION) - .values(location.owner().dbCode(),location.parent(),location.name(),null) + .values(location.owner().dbCode(),location.parent(),location.name(),location.description()) .execute(db).getGeneratedKeys(); long id = 0; if (rs.next()) id = rs.getLong(1); @@ -303,7 +303,17 @@ public class SqliteDb extends BaseDb implements StockDb { throw databaseException("Failed to save new location ({0})",location.name()); } } else { - throw databaseException("Updating locations not implemented"); + try { + update(TABLE_LOCATIONS) + .set(OWNER, PARENT_LOCATION_ID, NAME, DESCRIPTION) + .where(ID,equal(location.id())) + .prepare(db) + .apply(location.owner().dbCode(), location.parent(), location.name(), location.description()) + .close(); + return location.clear(); + } catch (SQLException e){ + throw databaseException("Updating location \"{0}\" not implemented",location.name()); + } } } diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java index 597b3ac..6bd164b 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java @@ -242,7 +242,7 @@ public class StockModule extends BaseHandler implements StockService { var owner = location.owner().resolve(); if (!assigned(owner,user)) throw forbidden("You are not allowed to alter the location of \"{0}\"!",location.name()); - var target = stockDb.loadLocation(locationId.longValue()); + var target = stockDb.loadLocation(destLocationId.longValue()); var locOwner = target.resolve().owner().resolve(); if (!assigned(locOwner,user)) throw forbidden("You are not allowed to modify \"{0}\"!",target.name()); From 8bf0790fca401627003282ea57af1474d005aead Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Wed, 22 Oct 2025 22:45:14 +0200 Subject: [PATCH 3/4] refactored location patching Signed-off-by: Stephan Richter --- .../umbrella/core/model/DbLocation.java | 23 ++++++++++++-- frontend/src/routes/stock/Index.svelte | 10 ++---- .../umbrella/stock/StockModule.java | 31 ++++++++++++------- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java b/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java index 87e9b58..26a9ae7 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java @@ -4,6 +4,8 @@ package de.srsoftware.umbrella.core.model; import static de.srsoftware.umbrella.core.Constants.*; import de.srsoftware.umbrella.core.api.Owner; +import org.json.JSONObject; + import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashSet; @@ -59,9 +61,24 @@ public class DbLocation extends Location { return parentLocationId; } - public DbLocation parent(DbLocation newParent) { - parentLocationId = newParent.id(); - dirtyFields.add(PARENT_LOCATION_ID); + public DbLocation patch(JSONObject json) { + for (var field : json.keySet()){ + boolean known = true; + switch (field) { + case PARENT_LOCATION_ID: + parentLocationId = json.getLong(field); + break; + case NAME: + name = json.getString(NAME); + break; + case DESCRIPTION: + description = json.getString(DESCRIPTION); + break; + default: + known = false; + } + if (known) dirtyFields.add(field); + } return this; } diff --git a/frontend/src/routes/stock/Index.svelte b/frontend/src/routes/stock/Index.svelte index 2be4886..5107bc2 100644 --- a/frontend/src/routes/stock/Index.svelte +++ b/frontend/src/routes/stock/Index.svelte @@ -60,8 +60,8 @@ } async function move_dragged_to(new_loc){ - const data = draggedItem ? { item : draggedItem.id, target: new_loc.id } : { location : draggedLocation.id, target: new_loc.id } - const url = api(draggedItem ? 'stock/move_item' : 'stock/move_location'); + const data = draggedItem ? { item : draggedItem.id, target: new_loc.id } : { parent_location_id: new_loc.id } + const url = api(draggedItem ? 'stock/move_item' : `stock/location/${draggedLocation.id}`); const res = await fetch(url,{ credentials : 'include', method : 'PATCH', @@ -125,10 +125,6 @@ onMount(load); - -

    {t('Stock')}

    @@ -169,4 +165,4 @@
    {/if} {/await} -
    \ No newline at end of file +
    diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java index 6bd164b..0b31807 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java @@ -114,7 +114,15 @@ public class StockModule extends BaseHandler implements StockService { if (user.isEmpty()) return unauthorized(ex); return switch (path.pop()){ case MOVE_ITEM -> patchMoveItem(user.get(), path,ex); - case MOVE_LOCATION -> patchMoveLocation(user.get(), path, ex); + case LOCATION -> { + try { + var id = Long.parseLong(path.pop()); + yield patchLocation(id, user.get(), ex); + } catch (NumberFormatException nfe){ + yield super.doPatch(path,ex); + } + + } case null -> patchItem(user.get(),ex); default -> super.doPatch(path,ex); }; @@ -233,21 +241,20 @@ public class StockModule extends BaseHandler implements StockService { return sendContent(ex,item); } - private boolean patchMoveLocation(UmbrellaUser user, Path path, HttpExchange ex) throws IOException { + private boolean patchLocation(long locationId, UmbrellaUser user, HttpExchange ex) throws IOException { var json = json(ex); - if (!(json.get(LOCATION) instanceof Number locationId)) throw missingFieldException(LOCATION); - if (!(json.get(TARGET) instanceof Number destLocationId)) throw missingFieldException(TARGET); - var location = stockDb.loadLocation(locationId.longValue()); - + var location = stockDb.loadLocation(locationId); var owner = location.owner().resolve(); - if (!assigned(owner,user)) throw forbidden("You are not allowed to alter the location of \"{0}\"!",location.name()); + if (!assigned(owner,user)) throw forbidden("You are not allowed to edit \"{0}\"!",location.name()); - var target = stockDb.loadLocation(destLocationId.longValue()); - var locOwner = target.resolve().owner().resolve(); - if (!assigned(locOwner,user)) throw forbidden("You are not allowed to modify \"{0}\"!",target.name()); + if (json.has(PARENT_LOCATION_ID) && json.get(PARENT_LOCATION_ID) instanceof Number parentId){ + var target = stockDb.loadLocation(parentId.longValue()); + var targetOwner = target.owner().resolve(); + if (!assigned(targetOwner,user)) throw forbidden("You are not allowed to edit \"{0}\"!",target.name()); + if (!targetOwner.equals(owner)) throw unprocessable("You may not move locations from one owner ({0}) to another ({1})",owner,targetOwner); + } - if (!locOwner.equals(owner)) throw unprocessable("You may not move locations from one owner ({0}) to another ({1})",owner,locOwner); - location = stockDb.save(location.parent(target)); + location = stockDb.save(location.patch(json)); return sendContent(ex,location); } From a73a660d43dc49a5a4d73d693c393d43b265ef68 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Wed, 22 Oct 2025 23:36:42 +0200 Subject: [PATCH 4/4] refactored moving of locations, implemented editing of location details, implemented raising locations to the top level Signed-off-by: Stephan Richter --- .../umbrella/core/model/DbLocation.java | 7 ++-- frontend/src/routes/stock/Index.svelte | 32 +++++++++++++++++-- .../srsoftware/umbrella/stock/SqliteDb.java | 5 +-- .../umbrella/stock/StockModule.java | 10 +++--- translations/src/main/resources/de.json | 1 + translations/src/main/resources/en.json | 1 + 6 files changed, 45 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java b/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java index 26a9ae7..23bb086 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/DbLocation.java @@ -2,15 +2,15 @@ package de.srsoftware.umbrella.core.model; import static de.srsoftware.umbrella.core.Constants.*; +import static de.srsoftware.umbrella.core.Util.markdown; import de.srsoftware.umbrella.core.api.Owner; -import org.json.JSONObject; - import java.sql.ResultSet; import java.sql.SQLException; import java.util.HashSet; import java.util.Map; import java.util.Set; +import org.json.JSONObject; public class DbLocation extends Location { private Owner owner; @@ -92,7 +92,8 @@ public class DbLocation extends Location { var map = super.toMap(); map.put(OWNER,owner.toMap()); map.put(NAME,name); - map.put(DESCRIPTION,description); + map.put(DESCRIPTION,Map.of(SOURCE,description,RENDERED,markdown(description))); + if (parentLocationId != null) map.put(PARENT_LOCATION_ID,parentLocationId); return map; } diff --git a/frontend/src/routes/stock/Index.svelte b/frontend/src/routes/stock/Index.svelte index 5107bc2..ac8d15a 100644 --- a/frontend/src/routes/stock/Index.svelte +++ b/frontend/src/routes/stock/Index.svelte @@ -4,9 +4,11 @@ import { error, yikes } from '../../warn.svelte'; import { t } from '../../translations.svelte'; - import Locations from './Locations.svelte'; import ItemList from './ItemList.svelte'; import ItemProps from './ItemProps.svelte'; + import LineEditor from '../../Components/LineEditor.svelte'; + import Locations from './Locations.svelte'; + import MarkdownEditor from '../../Components/MarkdownEditor.svelte'; import Notes from '../notes/RelatedNotes.svelte'; import Tags from '../tags/TagList.svelte'; @@ -122,6 +124,25 @@ loadProperties(); } + async function patchLocation(location,field,newValue){ + const data = {}; + data[field] = newValue; + console.log(data); + const url = api(`stock/location/${location.id}`); + const res = await fetch(url,{ + credentials: 'include', + method:'PATCH', + body:JSON.stringify(data) + }); + if (res.ok){ + yikes(); + return true; + } else { + error(res); + return false; + } + } + onMount(load); @@ -147,7 +168,14 @@ {:then data}
    {#if location} -

    {location.name}

    +

    + patchLocation(location,'name',newName)} /> + + {#if location.parent_location_id} + + {/if} +

    + patchLocation(location,'description',newDesc)} /> {/if} a.code.localeCompare(b.code))} bind:selected={item} drag_start={drag_item} />
    diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java index 0207854..b3138e2 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/SqliteDb.java @@ -289,10 +289,11 @@ public class SqliteDb extends BaseDb implements StockDb { @Override public DbLocation save(DbLocation location) { + var parentId = location.parent() == 0 ? null : location.parent(); if (location.id() == 0) { // new location try { var rs = insertInto(TABLE_LOCATIONS,OWNER,PARENT_LOCATION_ID,NAME,DESCRIPTION) - .values(location.owner().dbCode(),location.parent(),location.name(),location.description()) + .values(location.owner().dbCode(),location.parent() == 0 ? null : parentId,location.name(),location.description()) .execute(db).getGeneratedKeys(); long id = 0; if (rs.next()) id = rs.getLong(1); @@ -308,7 +309,7 @@ public class SqliteDb extends BaseDb implements StockDb { .set(OWNER, PARENT_LOCATION_ID, NAME, DESCRIPTION) .where(ID,equal(location.id())) .prepare(db) - .apply(location.owner().dbCode(), location.parent(), location.name(), location.description()) + .apply(location.owner().dbCode(), parentId, location.name(), location.description()) .close(); return location.clear(); } catch (SQLException e){ diff --git a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java index 0b31807..833d3a2 100644 --- a/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java +++ b/stock/src/main/java/de/srsoftware/umbrella/stock/StockModule.java @@ -248,10 +248,12 @@ public class StockModule extends BaseHandler implements StockService { if (!assigned(owner,user)) throw forbidden("You are not allowed to edit \"{0}\"!",location.name()); if (json.has(PARENT_LOCATION_ID) && json.get(PARENT_LOCATION_ID) instanceof Number parentId){ - var target = stockDb.loadLocation(parentId.longValue()); - var targetOwner = target.owner().resolve(); - if (!assigned(targetOwner,user)) throw forbidden("You are not allowed to edit \"{0}\"!",target.name()); - if (!targetOwner.equals(owner)) throw unprocessable("You may not move locations from one owner ({0}) to another ({1})",owner,targetOwner); + if (parentId.longValue() != 0L) { + var target = stockDb.loadLocation(parentId.longValue()); + var targetOwner = target.owner().resolve(); + if (!assigned(targetOwner, user)) throw forbidden("You are not allowed to edit \"{0}\"!", target.name()); + if (!targetOwner.equals(owner)) throw unprocessable("You may not move locations from one owner ({0}) to another ({1})", owner, targetOwner); + } } location = stockDb.save(location.patch(json)); diff --git a/translations/src/main/resources/de.json b/translations/src/main/resources/de.json index cadcc73..89aa252 100644 --- a/translations/src/main/resources/de.json +++ b/translations/src/main/resources/de.json @@ -170,6 +170,7 @@ "wiki": "Wiki" }, "month": "Monat", + "move_to_top": "nach ganz oben bewegen", "must_not_be_empty": "darf nicht leer sein", "name": "Name", diff --git a/translations/src/main/resources/en.json b/translations/src/main/resources/en.json index 383bafe..3d8613d 100644 --- a/translations/src/main/resources/en.json +++ b/translations/src/main/resources/en.json @@ -169,6 +169,7 @@ "wiki": "wiki" }, "month": "month", + "move_to_top": "move to top level", "must_not_be_empty": "must not be empty", "name": "Name",