Browse Source

working on transformation of legacy notes tables

Signed-off-by: Stephan Richter <s.richter@srsoftware.de>
feature/brute_force_protection
Stephan Richter 3 months ago
parent
commit
1df7a2bd3c
  1. 9
      backend/src/main/java/de/srsoftware/umbrella/backend/Application.java
  2. 1
      core/src/main/java/de/srsoftware/umbrella/core/Constants.java
  3. 4
      core/src/main/java/de/srsoftware/umbrella/core/api/NoteService.java
  4. 2
      frontend/src/Components/Menu.svelte
  5. 2
      frontend/src/routes/user/EditUser.svelte
  6. 57
      legacy/src/main/java/de/srsoftware/umbrella/legacy/NotesLegacy.java
  7. 6
      legacy/src/main/java/de/srsoftware/umbrella/legacy/UserLegacy.java
  8. 7
      notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java
  9. 4
      notes/src/main/java/de/srsoftware/umbrella/notes/NotesDb.java
  10. 103
      notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java
  11. 2
      task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java

9
backend/src/main/java/de/srsoftware/umbrella/backend/Application.java

@ -15,7 +15,8 @@ import de.srsoftware.umbrella.core.Util; @@ -15,7 +15,8 @@ import de.srsoftware.umbrella.core.Util;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.documents.DocumentApi;
import de.srsoftware.umbrella.items.ItemApi;
import de.srsoftware.umbrella.legacy.LegacyApi;
import de.srsoftware.umbrella.legacy.NotesLegacy;
import de.srsoftware.umbrella.legacy.UserLegacy;
import de.srsoftware.umbrella.markdown.MarkdownApi;
import de.srsoftware.umbrella.message.MessageSystem;
import de.srsoftware.umbrella.notes.NoteModule;
@ -69,7 +70,8 @@ public class Application { @@ -69,7 +70,8 @@ public class Application {
var companyModule = new CompanyModule(registry, config);
var documentApi = new DocumentApi(registry, config);
var itemApi = new ItemApi(registry, config);
var legacyApi = new LegacyApi(registry,config);
var userLegacy = new UserLegacy(registry,config);
var notesLegacy = new NotesLegacy(registry,config);
var markdownApi = new MarkdownApi(registry);
var notesModule = new NoteModule(registry,config);
var projectModule = new ProjectModule(registry, config);
@ -89,7 +91,8 @@ public class Application { @@ -89,7 +91,8 @@ public class Application {
timeModule .bindPath("/api/times") .on(server);
translationModule.bindPath("/api/translations").on(server);
userModule .bindPath("/api/user") .on(server);
legacyApi .bindPath("/legacy") .on(server);
notesLegacy .bindPath("/legacy/notes") .on(server);
userLegacy .bindPath("/legacy/user") .on(server);
webHandler .bindPath("/") .on(server);
server.setExecutor(Executors.newFixedThreadPool(threads));

1
core/src/main/java/de/srsoftware/umbrella/core/Constants.java

@ -167,6 +167,7 @@ public class Constants { @@ -167,6 +167,7 @@ public class Constants {
public static final String UMBRELLA = "Umbrella";
public static final String UNIT = "unit";
public static final String UNIT_PRICE = "unit_price";
public static final String URI = "uri";
public static final String URL = "url";
public static final String USER = "user";
public static final String USER_ID = "user_id";

4
core/src/main/java/de/srsoftware/umbrella/core/api/NoteService.java

@ -6,9 +6,9 @@ import de.srsoftware.umbrella.core.model.Note; @@ -6,9 +6,9 @@ import de.srsoftware.umbrella.core.model.Note;
import java.util.Map;
public interface NoteService {
void deleteEntity(String task, long taskId);
void deleteEntity(String task, String taskId);
Map<Long,Note> getNotes(String module, long entityId) throws UmbrellaException;
Map<Long,Note> getNotes(String module, String entityId) throws UmbrellaException;
Note save(Note note);
}

2
frontend/src/Components/Menu.svelte

@ -9,7 +9,7 @@ const router = useTinyRouter(); @@ -9,7 +9,7 @@ const router = useTinyRouter();
const modules = $state([]);
async function fetchModules(){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/legacy/modules`;
const url = `${location.protocol}//${location.host.replace('5173','8080')}/legacy/user/modules`;
const resp = await fetch(url,{credentials:'include'});
if (resp.ok){
const arr = await resp.json();

2
frontend/src/routes/user/EditUser.svelte

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
import { t } from '../../translations.svelte.js';
let { user_id } = $props();
let caption = $state(t('save_user'));
let caption = $state(t('save_object',{object:t('user')}));
let editUser = $state(null);
let message = $state(t('loading_data'));
let options = $state([]);

57
legacy/src/main/java/de/srsoftware/umbrella/legacy/NotesLegacy.java

@ -0,0 +1,57 @@ @@ -0,0 +1,57 @@
/* © SRSoftware 2025 */
package de.srsoftware.umbrella.legacy;
import static de.srsoftware.umbrella.core.Constants.URI;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.missingFieldException;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.unprocessable;
import com.sun.net.httpserver.HttpExchange;
import de.srsoftware.configuration.Configuration;
import de.srsoftware.tools.Path;
import de.srsoftware.umbrella.core.BaseHandler;
import de.srsoftware.umbrella.core.ModuleRegistry;
import java.io.IOException;
public class NotesLegacy extends BaseHandler {
private final ModuleRegistry registry;
private final Configuration config;
public NotesLegacy(ModuleRegistry registry, Configuration config) {
this.registry = registry;
this.config = config.subset("umbrella.modules").orElseThrow(() -> new RuntimeException("Missing configuration: umbrella.modules"));
}
@Override
public boolean doDelete(Path path, HttpExchange ex) throws IOException {
return super.doDelete(path, ex);
}
@Override
public boolean doGet(Path path, HttpExchange ex) throws IOException {
return super.doGet(path, ex);
}
@Override
public boolean doOptions(Path path, HttpExchange ex) throws IOException {
return super.doOptions(path, ex);
}
@Override
public boolean doPatch(Path path, HttpExchange ex) throws IOException {
return super.doPatch(path, ex);
}
@Override
public boolean doPost(Path path, HttpExchange ex) throws IOException {
addCors(ex);
var data = formData(ex);
var noteService = registry.noteService();
if (!(data.get(URI) instanceof String uri)) throw missingFieldException(URI);
var parts = uri.split(":",2);
if (parts.length<2) throw unprocessable("Expected URI to contain colon (:)!");
String module = parts[0];
String entityId = parts[1];
var notes = noteService.getNotes(module,entityId);
return super.doPost(path, ex);
}
}

6
legacy/src/main/java/de/srsoftware/umbrella/legacy/LegacyApi.java → legacy/src/main/java/de/srsoftware/umbrella/legacy/UserLegacy.java

@ -29,13 +29,13 @@ import java.time.Instant; @@ -29,13 +29,13 @@ import java.time.Instant;
import java.util.*;
import org.json.JSONObject;
public class LegacyApi extends BaseHandler {
public class UserLegacy extends BaseHandler {
private final Configuration config;
private final String messageUrl;
private final ModuleRegistry registry;
public LegacyApi(ModuleRegistry registry, Configuration config) {
public UserLegacy(ModuleRegistry registry, Configuration config) {
this.registry = registry;
this.config = config.subset("umbrella.modules").orElseThrow(() -> new RuntimeException("Missing configuration: umbrella.modules"));
this.messageUrl = null;
@ -270,7 +270,7 @@ public class LegacyApi extends BaseHandler { @@ -270,7 +270,7 @@ public class LegacyApi extends BaseHandler {
var keys = config.keys();
var match = false;
for (var key : keys){
var baseUrl = config.get(key + ".baseUrl").map(LegacyApi::stripTrailingSlash).orElse(null);
var baseUrl = config.get(key + ".baseUrl").map(UserLegacy::stripTrailingSlash).orElse(null);
if (domain.equals(baseUrl)){
match = true;
break;

7
notes/src/main/java/de/srsoftware/umbrella/notes/NoteModule.java

@ -35,7 +35,7 @@ public class NoteModule extends BaseHandler implements NoteService { @@ -35,7 +35,7 @@ public class NoteModule extends BaseHandler implements NoteService {
}
@Override
public void deleteEntity(String module, long entityId) {
public void deleteEntity(String module, String entityId) {
notesDb.deleteEntity(module,entityId);
}
@ -79,8 +79,7 @@ public class NoteModule extends BaseHandler implements NoteService { @@ -79,8 +79,7 @@ public class NoteModule extends BaseHandler implements NoteService {
notes = notesDb.list(user.get().id());
} else {
var head = path.pop();
long entityId = Long.parseLong(head);
notes = getNotes(module, entityId);
notes = getNotes(module, head);
}
var authors = notes.values().stream().map(Note::authorId).distinct().map(registry.userService()::loadUser).collect(Collectors.toMap(UmbrellaUser::id,UmbrellaUser::toMap));
return sendContent(ex, Map.of("notes",mapValues(notes),"authors",authors));
@ -137,7 +136,7 @@ public class NoteModule extends BaseHandler implements NoteService { @@ -137,7 +136,7 @@ public class NoteModule extends BaseHandler implements NoteService {
}
}
public Map<Long,Note> getNotes(String module, long entityId) throws UmbrellaException{
public Map<Long,Note> getNotes(String module, String entityId) throws UmbrellaException{
return notesDb.list(module,entityId);
}

4
notes/src/main/java/de/srsoftware/umbrella/notes/NotesDb.java

@ -7,7 +7,7 @@ import java.util.Map; @@ -7,7 +7,7 @@ import java.util.Map;
public interface NotesDb {
long delete(long noteId);
void deleteEntity(String module, long entityId);
void deleteEntity(String module, String entityId);
/**
* get all lists of a person
@ -21,7 +21,7 @@ public interface NotesDb { @@ -21,7 +21,7 @@ public interface NotesDb {
* @param entityId
* @return
*/
Map<Long, Note> list(String module, long entityId);
Map<Long, Note> list(String module, String entityId);
Note load(long noteId);

103
notes/src/main/java/de/srsoftware/umbrella/notes/SqliteDb.java

@ -11,6 +11,7 @@ import static java.text.MessageFormat.format; @@ -11,6 +11,7 @@ import static java.text.MessageFormat.format;
import static java.time.ZoneOffset.UTC;
import de.srsoftware.tools.jdbc.Query;
import de.srsoftware.umbrella.core.BaseDb;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Note;
import java.sql.Connection;
@ -18,58 +19,100 @@ import java.sql.SQLException; @@ -18,58 +19,100 @@ import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
public class SqliteDb implements NotesDb {
public class SqliteDb extends BaseDb implements NotesDb {
private static final int INITIAL_DB_VERSION = 1;
private static final System.Logger LOG = System.getLogger("NotesDB");
private final Connection db;
public SqliteDb(Connection conn) {
this.db = conn;
init();
super(conn);
}
private int createTables() {
createNotesTables();
return createSettingsTable();
protected int createTables() {
int currentVersion = createSettingsTable();
switch (currentVersion){
case 0:
createNotesTable();
case 1:
addModuleColumn();
addEntityIdColumn();
calcReferences();
dropUriColumn();
}
private int createSettingsTable() {
return setCurrentVersion(2);
}
private void addEntityIdColumn() {
var createTable = """
CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) NOT NULL);
ALTER TABLE notes
ADD COLUMN entity_id VARCHAR(255);
""";
try {
var stmt = db.prepareStatement(format(createTable,TABLE_SETTINGS, KEY, VALUE));
var stmt = db.prepareStatement(createTable);
stmt.execute();
stmt.close();
} catch (SQLException e) {
LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_SETTINGS,e);
LOG.log(ERROR,"Failed to add \"entity_id\" column to table {0}",TABLE_NOTES,e);
throw new RuntimeException(e);
}
}
Integer version = null;
private void addModuleColumn() {
var createTable = """
ALTER TABLE notes
ADD COLUMN module VARCHAR(20);
""";
try {
var rs = select(VALUE).from(TABLE_SETTINGS).where(KEY, equal(DB_VERSION)).exec(db);
if (rs.next()) version = rs.getInt(VALUE);
rs.close();
if (version == null) {
version = INITIAL_DB_VERSION;
insertInto(TABLE_SETTINGS, KEY, VALUE).values(DB_VERSION,version).execute(db).close();
var stmt = db.prepareStatement(createTable);
stmt.execute();
stmt.close();
} catch (SQLException e) {
LOG.log(ERROR,"Failed to add \"module\" column to table {0}",TABLE_NOTES,e);
throw new RuntimeException(e);
}
}
private void calcReferences(){
var createTable = """
UPDATE notes
SET module = SUBSTR(uri, 1, INSTR(uri, ':') - 1),
entity_id = SUBSTR(uri, INSTR(uri, ':') + 1);
""";
try {
var stmt = db.prepareStatement(createTable);
stmt.execute();
stmt.close();
} catch (SQLException e) {
LOG.log(ERROR,"Failed fill \"module\" and \"entity_id\" columns",e);
throw new RuntimeException(e);
}
}
return version;
private void createNotesTable() {
var createTable = """
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY,
user_id INT NOT NULL,
uri VARCHAR(255) NOT NULL,
note TEXT NOT NULL,
timestamp INT)""";
try {
var stmt = db.prepareStatement(createTable);
stmt.execute();
stmt.close();
} catch (SQLException e) {
LOG.log(ERROR,ERROR_READ_TABLE,DB_VERSION,TABLE_SETTINGS,e);
LOG.log(ERROR,ERROR_FAILED_CREATE_TABLE,TABLE_NOTES,e);
throw new RuntimeException(e);
}
}
private void createNotesTables() {
private void createNewNotesTable() {
var createTable = """
CREATE TABLE IF NOT EXISTS "{0}" (
{1} INTEGER NOT NULL PRIMARY KEY,
{2} TEXT NOT NULL,
{3} VARCHAR(20) NOT NULL,
{4} INTEGER NOT NULL,
{4} VARCHAR(255) NOT NULL,
{5} INTEGER NOT NULL,
{6} DATETIME NOT NULL
)""";
@ -96,7 +139,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( @@ -96,7 +139,7 @@ CREATE TABLE IF NOT EXISTS "{0}" (
}
@Override
public void deleteEntity(String module, long entityId) {
public void deleteEntity(String module, String entityId) {
try {
Query.delete().from(TABLE_NOTES)
.where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId))
@ -106,6 +149,18 @@ CREATE TABLE IF NOT EXISTS "{0}" ( @@ -106,6 +149,18 @@ CREATE TABLE IF NOT EXISTS "{0}" (
}
}
private void dropUriColumn(){
var createTable = "ALTER TABLE notes DROP COLUMN uri";
try {
var stmt = db.prepareStatement(createTable);
stmt.execute();
stmt.close();
} catch (SQLException e) {
LOG.log(ERROR,"Failed drop \"uri\" column",e);
throw new RuntimeException(e);
}
}
private void init(){
var version = createTables();
LOG.log(INFO,"Updated task db to version {0}",version);
@ -128,7 +183,7 @@ CREATE TABLE IF NOT EXISTS "{0}" ( @@ -128,7 +183,7 @@ CREATE TABLE IF NOT EXISTS "{0}" (
}
@Override
public Map<Long, Note> list(String module, long entityId) {
public Map<Long, Note> list(String module, String entityId) {
try {
var notes = new HashMap<Long, Note>();
var rs = select(ALL).from(TABLE_NOTES).where(MODULE,equal(module)).where(ENTITY_ID,equal(entityId)).exec(db);

2
task/src/main/java/de/srsoftware/umbrella/task/TaskModule.java

@ -55,7 +55,7 @@ public class TaskModule extends BaseHandler implements TaskService { @@ -55,7 +55,7 @@ public class TaskModule extends BaseHandler implements TaskService {
var member = task.members().get(user.id());
if (member == null || !member.mayWrite()) throw forbidden("You are not allowed to delete {0}",task.name());
taskDb.delete(task);
registry.noteService().deleteEntity(TASK,taskId);
registry.noteService().deleteEntity(TASK,""+taskId);
registry.tagService().deleteEntity(TASK,taskId);
return sendContent(ex,Map.of(DELETED,taskId));
}

Loading…
Cancel
Save