refactoring objects in preparation for:

refactoring journal database to contain object ids for:
querying journal for objects
This commit is contained in:
2026-07-27 09:22:50 +02:00
parent c8ad603fca
commit e614880d71
11 changed files with 97 additions and 74 deletions
@@ -6,6 +6,7 @@ import static java.util.Optional.*;
import de.srsoftware.tools.Diff;
import de.srsoftware.tools.Mappable;
import de.srsoftware.umbrella.core.model.ObjectWithId;
import de.srsoftware.umbrella.core.model.Translatable;
import de.srsoftware.umbrella.core.model.UmbrellaUser;
import java.util.Collection;
@@ -14,15 +15,15 @@ import java.util.Map;
import java.util.Optional;
import org.json.JSONObject;
public abstract class Event<Payload extends Mappable> {
public abstract class Event<Payload extends ObjectWithId> {
public enum EventType {
CREATE,
MEMBER_ADDED,
UPDATE,
DELETE;
}
}
private final UmbrellaUser initiator;
private final String module;
private final Payload payload;
@@ -39,10 +40,10 @@ public abstract class Event<Payload extends Mappable> {
public Event(UmbrellaUser initiator, String module, Payload payload, Map<String, Object> oldData){
this.initiator = initiator;
this.module = module;
this.payload = payload;
this.module = module;
this.payload = payload;
this.eventType = EventType.UPDATE;
this.oldData = oldData;
this.oldData = oldData;
}
public abstract Collection<UmbrellaUser> audience();
@@ -98,6 +99,10 @@ public abstract class Event<Payload extends Mappable> {
return module;
}
public long objectId() {
return payload.id();
};
protected Map<String, Object> oldData() {
return oldData;
}
@@ -36,6 +36,10 @@ public class ItemEvent extends Event<Item>{
return t("{user} added \"{item}\" to \"{location}\"", USER,initiator().name(), ITEM, payload().name(), LOCATION, loc);
}
@Override
public long objectId() {
return payload().id();
}
@Override
public Translatable subject() {
@@ -78,6 +78,11 @@ public class ProjectEvent extends Event<Project>{
return t("You can view/edit this project at {base_url}/project/{id}/view",ID,payload().id());
}
@Override
public long objectId() {
return payload().id();
}
@Override
public Translatable subject() {
return switch (eventType()){
@@ -62,6 +62,11 @@ public class TransactionEvent extends Event<Transaction> {
return t("You can view/edit this transaction at {base_url}/account/{id}", ID, payload().accountId());
}
@Override
public long objectId() {
return payload().id();
}
@Override
public Translatable subject() {
var user = initiator().name();
@@ -68,6 +68,10 @@ public class WikiEvent extends Event<WikiPage>{
return t("You can view/edit this wiki page at {base_url}/wiki/{id}/view",ID,payload().id());
}
@Override
public long objectId() {
return payload().id();
}
@Override
public Translatable subject() {
@@ -4,7 +4,6 @@ package de.srsoftware.umbrella.core.model;
import static de.srsoftware.umbrella.core.Util.mapMarkdown;
import static de.srsoftware.umbrella.core.constants.Field.*;
import de.srsoftware.tools.Mappable;
import de.srsoftware.umbrella.core.api.Owner;
import de.srsoftware.umbrella.core.constants.Field;
import java.sql.ResultSet;
@@ -12,16 +11,16 @@ import java.sql.SQLException;
import java.util.*;
import org.json.JSONObject;
public class Item implements Mappable {
private long id, ownerNumber; // id is the database key, number the owner-relative id
private Owner owner;
public class Item extends ObjectWithId {
private long ownerNumber; // id is the database key, number the owner-relative id
private final Owner owner;
private String code, description, name;
private Location location;
private Collection<Property> properties;
private Set<String> dirtyFields = new HashSet<>();
private final Collection<Property> properties;
private final Set<String> dirtyFields = new HashSet<>();
public Item(long id, Owner owner, long ownerNumber, Location location, String code, String name, String description) {
this.id = id;
super(id);
this.owner = owner;
this.ownerNumber = ownerNumber;
this.location = location;
@@ -48,15 +47,6 @@ public class Item implements Mappable {
return !dirtyFields.isEmpty();
}
public long id(){
return id;
}
public Item id(long newVal) {
id = newVal;
return this;
}
public Location location(){
return location;
}
@@ -121,14 +111,13 @@ public class Item implements Mappable {
@Override
public Map<String, Object> toMap() {
var map = new HashMap<String,Object>();
map.put(OWNER,owner.toMap());
map.put(ID,id);
map.put(LOCATION,location.toMap());
map.put(Field.CODE,code);
map.put(NAME,name);
map.put(DESCRIPTION,mapMarkdown(description));
map.put(OWNER_NUMBER,ownerNumber);
var map = super.map(
OWNER,owner.toMap(),
LOCATION,location.toMap(),
Field.CODE,code,
NAME,name,
DESCRIPTION,mapMarkdown(description),
OWNER_NUMBER,ownerNumber);
if (properties != null) map.put(PROPERTIES,properties.stream().map(Property::toMap).toList());
return map;
}
@@ -0,0 +1,30 @@
package de.srsoftware.umbrella.core.model;
import de.srsoftware.tools.Mappable;
import de.srsoftware.umbrella.core.constants.Field;
import java.security.InvalidParameterException;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class ObjectWithId implements Mappable {
private final long id;
public ObjectWithId(long id){
this.id = id;
}
public long id(){
return id;
}
protected Map<String, Object> map(Object ... keysAndValues) {
if (keysAndValues.length % 2 != 0) throw new InvalidParameterException("Expected even number of keys and parameters!");
var map = new HashMap<String, Object>();
map.put(Field.ID,id);
for (var idx = 0; idx<keysAndValues.length; idx+=2) map.put(keysAndValues[idx].toString(),keysAndValues[idx+1]);
return map;
}
}
@@ -6,27 +6,25 @@ import static de.srsoftware.umbrella.core.Util.mapMarkdown;
import static de.srsoftware.umbrella.core.constants.Field.*;
import static de.srsoftware.umbrella.core.model.Status.PREDEFINED;
import de.srsoftware.tools.Mappable;
import de.srsoftware.umbrella.core.constants.Field;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import org.json.JSONObject;
public class Project implements Mappable {
public class Project extends ObjectWithId {
private final Map<Long,Member> members;
private final Collection<Status> allowedStates;
private boolean showClosed;
private Long companyId;
private int status;
private String name;
private final long id;
private String description;
private final Set<String> dirtyFields = new HashSet<>();
private final Map<String,String> tagColors = new HashMap<>();
public Project(long id, String name, String description, int status, Long companyId, boolean showClosed, Map<Long,Member> members, Collection<Status> allowedStates) {
this.id = id;
super(id);
this.name = name;
this.description = description;
this.status = status;
@@ -67,10 +65,6 @@ public class Project implements Mappable {
return members.containsKey(user.id());
}
public long id(){
return id;
}
public boolean isDirty() {
return !dirtyFields.isEmpty();
}
@@ -126,23 +120,21 @@ public class Project implements Mappable {
@Override
public Map<String, Object> toMap() {
var map = new HashMap<String, Object>();
var memberMap = new HashMap<Long,Map<String,Object>>();
if (members != null) for (var entry : members.entrySet()){
memberMap.put(entry.getKey(),entry.getValue().toMap());
}
map.put(ID,id);
map.put(NAME,name);
map.put(DESCRIPTION,mapMarkdown(description));
map.put(STATUS,status);
map.put(COMPANY_ID,companyId);
map.put(SHOW_CLOSED,showClosed);
map.put(MEMBERS,memberMap);
var stateMap = new HashMap<Integer,String>();
for (var state : allowedStates) stateMap.put(state.code(),state.name());
map.put(Field.ALLOWED_STATES,stateMap);
map.put(TAG_COLORS,tagColors);
return map;
return super.map(
NAME,name,
DESCRIPTION,mapMarkdown(description),
STATUS,status,
COMPANY_ID,companyId,
SHOW_CLOSED,showClosed,
MEMBERS,memberMap,
Field.ALLOWED_STATES,stateMap,
TAG_COLORS,tagColors);
}
@Override
@@ -14,17 +14,17 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class Transaction implements Mappable {
private long accountId, id;
public class Transaction extends ObjectWithId {
private final long accountId;
private LocalDateTime date;
private IdOrString source, destination;
private double amount;
private String purpose;
private Set<String> tags;
private HashSet<String> dirtyFields = new HashSet<>();
private final Set<String> tags;
private final HashSet<String> dirtyFields = new HashSet<>();
public Transaction(long id, long accountId, LocalDateTime date, IdOrString source, IdOrString destination, double amount, String purpose, Set<String> tags){
this.id = id;
super(id);
this.accountId = accountId;
this.date = date;
this.source = source;
@@ -77,10 +77,6 @@ public class Transaction implements Mappable {
return this;
}
public long id(){
return id;
}
public boolean isDirty(){
return !dirtyFields.isEmpty();
}
@@ -123,8 +119,7 @@ public class Transaction implements Mappable {
@Override
public Map<String, Object> toMap() {
return Map.of(
Field.ID, id,
return super.map(
Field.ACCOUNT, accountId,
Field.DATE, date.toLocalDate(),
Field.SOURCE, source.toMap(),
@@ -10,16 +10,14 @@ import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
import static de.srsoftware.umbrella.core.model.Translatable.t;
import static java.lang.String.join;
import de.srsoftware.tools.Mappable;
import de.srsoftware.umbrella.core.api.UserService;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import org.json.JSONObject;
public class WikiPage implements Mappable {
public class WikiPage extends ObjectWithId {
private final long id;
private String title;
private int version;
private final Set<Integer> versions = new TreeSet<>();
@@ -29,7 +27,7 @@ public class WikiPage implements Mappable {
private boolean guestAllowed = false;
public WikiPage(long id, String title, int version, String content) {
this.id = id;
super(id);
this.version = version;
this.content = content;
this.title = title;
@@ -60,10 +58,6 @@ public class WikiPage implements Mappable {
dirtyFields.add(GUEST_ALLOWED);
}
public long id(){
return id;
}
public boolean isDirty(String field) {
return dirtyFields.contains(field);
}
@@ -146,8 +140,7 @@ public class WikiPage implements Mappable {
var memberMap = new HashMap<Long,Map<String,Object>>();
for (var entry : members.entrySet()) memberMap.put(entry.getKey(),entry.getValue().toMap());
return Map.of(
ID,id,
return map(
CONTENT,mapMarkdown(content),
GUEST_ALLOWED,guestAllowed,
MEMBERS,memberMap,
@@ -38,11 +38,12 @@ public class SqliteDb extends BaseDb implements JournalDb{
{2} LONG NOT NULL,
{3} INTEGER,
{4} VARCHAR(255) NOT NULL,
{5} VARCHAR(16) NOT NULL,
{6} TEXT
{5} VARCHAR(255),
{6} VARCHAR(16) NOT NULL,
{7} TEXT
);
""";
sql = format(sql,TABLE_JOURNAL,ID,TIMESTAMP,USER_ID,MODULE,ACTION,DESCRIPTION);
sql = format(sql,TABLE_JOURNAL,ID,TIMESTAMP,USER_ID,MODULE,ENTITY_ID,ACTION,DESCRIPTION);
try {
db.prepareStatement(sql).execute();
} catch (SQLException e) {
@@ -54,8 +55,8 @@ public class SqliteDb extends BaseDb implements JournalDb{
public void logEvent(Event<?> event) {
try {
var timestamp = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
insertInto(TABLE_JOURNAL,TIMESTAMP,USER_ID,MODULE,ACTION,DESCRIPTION)
.values(timestamp,event.initiator().id(), event.module(), event.eventType(), event.describe())
insertInto(TABLE_JOURNAL,TIMESTAMP,USER_ID,MODULE,ENTITY_ID,ACTION,DESCRIPTION)
.values(timestamp,event.initiator().id(), event.module(), event.objectId(), event.eventType(), event.describe())
.execute(db).close();
} catch (SQLException e) {
throw databaseException(ERROR_WRITE_EVENT,event.eventType(),event.initiator().name());