working on adding new properties to existing items

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
This commit is contained in:
2025-10-15 00:21:08 +02:00
parent 48128c5bf4
commit 846ef4a27a
9 changed files with 191 additions and 57 deletions

View File

@@ -50,6 +50,20 @@ public class SqliteDb extends BaseDb implements StockDb {
super(connection);
}
@Override
public void addProperty(long ownerId, long itemId, long existingPropId, Object value) {
try {
insertInto(TABLE_ITEM_PROPERTIES,OWNER,ITEM_ID,PROPERTY_ID,VALUE).values(ownerId,itemId,existingPropId,value).execute(db);
} catch (SQLException e) {
throw databaseException("Failed to add new property to item {0}",itemId);
}
}
@Override
public void addProperty(long ownerId, long itemId, String name, Object value, String unit) {
// TODO
}
private void createIntermediateItemsTable() throws SQLException { // create intermediate table
var sql = "CREATE TABLE IF NOT EXISTS items_temp ({0} LONG NOT NULL, {1} LONG NOT NULL, {2} VARCHAR(255), {3} VARCHAR(255) NOT NULL, {4} LONG NOT NULL, PRIMARY KEY({0}, {1}))";
sql = format(sql, OWNER, ID, CODE, NAME, LOCATION_ID);
@@ -204,6 +218,19 @@ public class SqliteDb extends BaseDb implements StockDb {
}
}
@Override
public Collection<Property> listProperties() {
try {
var rs = select(ALL).from(TABLE_PROPERTIES).exec(db);
var list = new ArrayList<Property>();
while (rs.next()) list.add(Property.of(rs));
rs.close();
return list;
} catch (SQLException e){
throw databaseException("Failed to load properties!");
}
}
@Override
public Collection<Location> listUserLocations(UmbrellaUser user) {
try {

View File

@@ -1,15 +1,16 @@
/* © SRSoftware 2025 */
package de.srsoftware.umbrella.stock;
import de.srsoftware.umbrella.core.model.Company;
import de.srsoftware.umbrella.core.model.Item;
import de.srsoftware.umbrella.core.model.Location;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import de.srsoftware.umbrella.core.model.*;
import java.util.Collection;
public interface StockDb {
void addProperty(long ownerId, long itemId, long existingPropId, Object value);
void addProperty(long ownerId, long itemId, String name, Object value, String unit);
Collection<Location> listChildLocations(long parentId);
Collection<Location> listCompanyLocations(Company company);
Collection<Item> listItemsAt(long locationId);
Collection<Property> listProperties();
Collection<Location> listUserLocations(UmbrellaUser userId);
}

View File

@@ -1,14 +1,15 @@
/* © SRSoftware 2025 */
package de.srsoftware.umbrella.stock;
import static de.srsoftware.tools.Optionals.nullIfEmpty;
import static de.srsoftware.umbrella.core.ConnectionProvider.connect;
import static de.srsoftware.umbrella.core.Constants.ID;
import static de.srsoftware.umbrella.core.Constants.NAME;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.ModuleRegistry.companyService;
import static de.srsoftware.umbrella.core.ModuleRegistry.userService;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
import static de.srsoftware.umbrella.stock.Constants.*;
import static java.lang.System.Logger.Level.WARNING;
import static java.text.MessageFormat.format;
import static java.util.Comparator.comparing;
import com.sun.net.httpserver.HttpExchange;
@@ -19,18 +20,17 @@ import de.srsoftware.umbrella.core.BaseHandler;
import de.srsoftware.umbrella.core.ModuleRegistry;
import de.srsoftware.umbrella.core.api.StockService;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Item;
import de.srsoftware.umbrella.core.model.Location;
import de.srsoftware.umbrella.core.model.Token;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import de.srsoftware.umbrella.core.model.*;
import org.json.JSONObject;
import java.io.IOException;
import java.util.*;
public class StockApi extends BaseHandler implements StockService {
public class StockModule extends BaseHandler implements StockService {
private final StockDb stockDb;
public StockApi(Configuration config) throws UmbrellaException {
public StockModule(Configuration config) throws UmbrellaException {
super();
var dbFile = config.get(CONFIG_DATABASE).orElseThrow(() -> missingFieldException(CONFIG_DATABASE));
stockDb = new SqliteDb(connect(dbFile));
@@ -46,15 +46,16 @@ public class StockApi extends BaseHandler implements StockService {
if (user.isEmpty()) return unauthorized(ex);
var head = path.pop();
return switch (head) {
case ITEMS_AT -> {
case LOCATION -> {
try {
var id = Long.parseLong(path.pop());
yield getItemsAt(user.get(),id,ex);
yield getLocation(user.get(),id,ex);
} catch (Exception e){
yield super.doGet(path,ex);
}
}
case LOCATIONS -> getLocations(path,user.get(),ex);
case PROPERTIES -> getProperties(ex);
case null, default -> super.doGet(path,ex);
};
} catch (UmbrellaException e){
@@ -62,7 +63,30 @@ public class StockApi extends BaseHandler implements StockService {
}
}
private boolean getItemsAt(UmbrellaUser user, long locationId, HttpExchange ex) throws IOException {
@Override
public boolean doPost(Path path, HttpExchange ex) throws IOException {
addCors(ex);
try {
Optional<Token> 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 PROPERTY -> postProperty(user.get(),ex);
case null, default -> super.doPost(path,ex);
};
} catch (UmbrellaException e){
return send(ex,e);
}
}
private boolean getChildLocations(UmbrellaUser user, long parentId, HttpExchange ex) throws IOException {
LOG.log(WARNING,"No security check implemented for {0}.getChildLocations(user, parentId, ex)!",getClass().getSimpleName()); // TODO check, that user is allowed to request that location
return sendContent(ex, stockDb.listChildLocations(parentId).stream().sorted(comparing(l -> l.name().toLowerCase())).map(Location::toMap));
}
private boolean getLocation(UmbrellaUser user, long locationId, HttpExchange ex) throws IOException {
return sendContent(ex, stockDb.listItemsAt(locationId).stream().map(Item::toMap).toList());
}
@@ -83,10 +107,8 @@ public class StockApi extends BaseHandler implements StockService {
};
}
private boolean getChildLocations(UmbrellaUser user, long parentId, HttpExchange ex) throws IOException {
LOG.log(WARNING,"No security check implemented for {0}.getChildLocations(user, parentId, ex)!",getClass().getSimpleName()); // TODO check, that user is allowed to request that location
return sendContent(ex, stockDb.listChildLocations(parentId).stream().sorted(comparing(l -> l.name().toLowerCase())).map(Location::toMap));
private boolean getProperties(HttpExchange ex) throws IOException {
return sendContent(ex,stockDb.listProperties().stream().map(Property::toMap).toList());
}
private boolean getUserLocations(UmbrellaUser user, HttpExchange ex) throws IOException {
@@ -109,6 +131,35 @@ public class StockApi extends BaseHandler implements StockService {
return sendContent(ex, result);
}
private boolean postProperty(UmbrellaUser user, HttpExchange ex) throws IOException {
var json = json(ex);
if (!(json.get(ID) instanceof Number id)) throw missingFieldException(ID);
if (!(json.get(FIELD_ITEM) instanceof JSONObject itemData)) throw missingFieldException(FIELD_ITEM);
if (!(itemData.get(OWNER) instanceof JSONObject owner)) throw missingFieldException(OWNER);
if (!(json.get("add_prop") instanceof JSONObject propData)) throw missingFieldException("add_prop");
if (!propData.has(VALUE)) throw missingFieldException(VALUE);
var value = propData.get(VALUE);
if (value == null) throw missingFieldException(VALUE);
var keys = owner.keySet();
if (keys.size() != 1) throw unprocessable("{0} expected to have only one child!",OWNER);
var key = new ArrayList<>(keys).getFirst();
var ownerId = switch (key) {
case COMPANY -> -json.getLong(key);
case USER -> json.getLong(key);
case null, default -> throw invalidFieldException(format("Single child of {0}", OWNER), format("either {0} or {1}", COMPANY, USER));
};
if (propData.get("existing_prop_id") instanceof Number existingPropId && existingPropId.longValue() != 0L){
stockDb.addProperty(ownerId,id.longValue(),existingPropId.longValue(),value);
} else {
if (!(propData.get("new_prop") instanceof JSONObject newProp)) throw unprocessable("data must contain either add_prop.existing_prop_id or add_prop.new_prop!");
if (!(newProp.get(NAME) instanceof String name) || name.isBlank()) throw unprocessable("data.add_prop.new_prop does not contain name!");
var unit = newProp.get(UNIT) instanceof String u ? nullIfEmpty(u) : null;
stockDb.addProperty(ownerId,id.longValue(),name,value,unit);
}
return sendEmptyResponse(500,ex);
}
@Override
public Collection<Object> redefineMe(long company_id) {
return List.of();