Browse Source

refactoring

kanban
Stephan Richter 4 months ago
parent
commit
08838e8ddc
  1. 10
      core/src/main/java/de/srsoftware/umbrella/core/model/Member.java
  2. 3
      core/src/main/java/de/srsoftware/umbrella/core/model/Project.java
  3. 1
      documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java
  4. 2
      frontend/src/App.svelte
  5. 9
      frontend/src/Components/Menu.svelte
  6. 6
      frontend/src/routes/project/List.svelte
  7. 66
      frontend/src/routes/project/View.svelte
  8. 7
      project/src/main/java/de/srsoftware/umbrella/project/ProjectDb.java
  9. 44
      project/src/main/java/de/srsoftware/umbrella/project/ProjectModule.java
  10. 45
      project/src/main/java/de/srsoftware/umbrella/project/SqliteDb.java
  11. 31
      translations/src/main/resources/de.json
  12. 2
      user/src/main/java/de/srsoftware/umbrella/user/UserModule.java

10
core/src/main/java/de/srsoftware/umbrella/core/model/Member.java

@ -2,16 +2,14 @@ @@ -2,16 +2,14 @@
package de.srsoftware.umbrella.core.model;
import de.srsoftware.tools.Mappable;
import static de.srsoftware.umbrella.core.Constants.*;
import de.srsoftware.tools.Mappable;
import java.util.Map;
import static de.srsoftware.umbrella.core.Constants.PERMISSION;
import static de.srsoftware.umbrella.core.Constants.USER;
public record Member(UmbrellaUser user, Permission permission) implements Mappable {
public record Member(long userId, Permission permission) implements Mappable {
@Override
public Map<String, Object> toMap() {
return Map.of(USER,user.toMap(),PERMISSION,permission.name());
return Map.of(USER_ID,userId,PERMISSION,permission.name());
}
}

3
core/src/main/java/de/srsoftware/umbrella/core/model/Project.java

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
package de.srsoftware.umbrella.core.model;
import static de.srsoftware.umbrella.core.Constants.*;
import static de.srsoftware.umbrella.core.Util.markdown;
import de.srsoftware.tools.Mappable;
import java.sql.ResultSet;
@ -47,7 +48,7 @@ public record Project(long id, String name, String description, Status status, L @@ -47,7 +48,7 @@ public record Project(long id, String name, String description, Status status, L
var map = new HashMap<String, Object>();
map.put(ID,id);
map.put(NAME,name);
map.put(DESCRIPTION,description);
map.put(DESCRIPTION,Map.of(SOURCE,description,RENDERED,markdown(description)));
map.put(STATUS,Map.of(STATUS_CODE,status.code(), NAME,status.name()));
map.put(COMPANY_ID,companyId);
map.put(SHOW_CLOSED,showClosed);

1
documents/src/main/java/de/srsoftware/umbrella/documents/DocumentApi.java

@ -150,7 +150,6 @@ public class DocumentApi extends BaseHandler { @@ -150,7 +150,6 @@ public class DocumentApi extends BaseHandler {
case SETTINGS -> getDocumentSettings(ex,docId,user.get());
default -> super.doGet(path,ex);
};
}
};
} catch (NumberFormatException ignored) {

2
frontend/src/App.svelte

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
import SendDoc from "./routes/document/Send.svelte";
import User from "./routes/user/User.svelte";
import ViewDoc from "./routes/document/View.svelte";
import ViewPrj from "./routes/project/View.svelte";
let translations_ready = $state(false);
onMount(async () => {
@ -48,6 +49,7 @@ @@ -48,6 +49,7 @@
<Route path="/message/settings" component={Messages} />
<Route path="/project" component={ProjectList} />
<Route path="/project/add" component={ProjectAdd} />
<Route path="/project/:id/view" component={ViewPrj} />
<Route path="/search" component={Search} />
<Route path="/user" component={User} />
<Route path="/user/create" component={EditUser} />

9
frontend/src/Components/Menu.svelte

@ -13,7 +13,10 @@ async function fetchModules(){ @@ -13,7 +13,10 @@ async function fetchModules(){
const resp = await fetch(url,{credentials:'include'});
if (resp.ok){
const arr = await resp.json();
for (let entry of arr) modules.push({name:t(entry.module),url:entry.url});
for (let entry of arr) {
let name = t('module.'+entry.module);
if (name) modules.push({name:name,url:entry.url});
}
} else {
console.log('error');
}
@ -32,9 +35,7 @@ onMount(fetchModules); @@ -32,9 +35,7 @@ onMount(fetchModules);
<a onclick={() => router.navigate('/document')}>{t('documents')}</a>
<a onclick={() => router.navigate('/project')}>{t('projects')}</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 }
<a onclick={logout}>{t('logout')}</a>
{/if}

6
frontend/src/routes/project/List.svelte

@ -48,8 +48,8 @@ @@ -48,8 +48,8 @@
</tr>
</thead>
<tbody>
{#each Object.entries(projects) as [id,project]}
<tr onclick={() => router.navigate(`/project/${project.id}/view`)}>
{#each Object.entries(projects) as [pid,project]}
<tr onclick={() => router.navigate(`/project/${pid}/view`)}>
<td>{project.name}</td>
<td>
{#if project.company_id}
@ -60,7 +60,7 @@ @@ -60,7 +60,7 @@
{t("state_"+project.status.name.toLowerCase())}
</td>
<td>
{#each project.members as member,idx}
{#each Object.entries(project.members) as [uid,member]}
<div>{member.user.name}</div>
{/each}
</td>

66
frontend/src/routes/project/View.svelte

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
<script>
import { t } from '../../translations.svelte.js';
import { onMount } from 'svelte';
let { id } = $props();
let project = $state(null);
let error = $state(null);
async function loadProject(){
const url = `${location.protocol}//${location.host.replace('5173','8080')}/api/project/${id}`;
const resp = await fetch(url,{credentials:'include'});
if (resp.ok){
project = await resp.json();
error = null;
} else {
error = await resp.text();
}
}
onMount(loadProject);
</script>
{#if error}
<span class="error">{error}</span>
{/if}
{#if project}
<table>
<tbody>
<tr>
<th>{t('project')}</th>
<td>{project.name}</td>
</tr>
<tr>
<th>{t('context')}</th>
<td>
<button>{t('files')}</button>
<button>{t('models')}</button>
<button>{t('times')}</button>
</td>
</tr>
<tr>
<th>{t('description')}</th>
<td>{@html project.description.rendered}</td>
</tr>
<tr>
<th>{t('estimated_time')}</th>
<td class="error">TODO</td>
</tr>
<tr>
<th>{t('tasks')}</th>
<td class="error">TODO</td>
</tr>
<tr>
<th>{t('members')}</th>
<td>
<ul>
{#each Object.entries(project.members) as [uid,member]}
<li>{member.user.name}: {t('permission.'+member.permission)}</li>
{/each}
</ul>
</td>
</tr>
</tbody>
</table>
{/if}

7
project/src/main/java/de/srsoftware/umbrella/project/ProjectDb.java

@ -1,14 +1,15 @@ @@ -1,14 +1,15 @@
/* © SRSoftware 2025 */
package de.srsoftware.umbrella.project;
import de.srsoftware.umbrella.core.api.UserService;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Project;
import java.util.Map;
public interface ProjectDb {
Map<Long, Project> ofCompany(long companyId, boolean includeClosed, UserService userService) throws UmbrellaException;
Map<Long, Project> ofUser(long userId, boolean includeClosed, UserService userService) throws UmbrellaException;
Map<Long, Project> ofCompany(long companyId, boolean includeClosed) throws UmbrellaException;
Map<Long, Project> ofUser(long userId, boolean includeClosed) throws UmbrellaException;
Project save(Project prj) throws UmbrellaException;
Project load(long projectId) throws UmbrellaException;
}

44
project/src/main/java/de/srsoftware/umbrella/project/ProjectModule.java

@ -53,8 +53,15 @@ public class ProjectModule extends BaseHandler implements ProjectService { @@ -53,8 +53,15 @@ public class ProjectModule extends BaseHandler implements ProjectService {
return switch (head) {
case LIST -> listUserProjects(ex,user.get());
case null -> postProject(ex,user.get());
default -> {
var projectId = Long.parseLong(head);
head = path.pop();
yield switch (head){
case null -> getProject(ex,projectId,user.get());
default -> super.doGet(path,ex);
};
}
};
} catch (UmbrellaException e){
return send(ex,e);
}
@ -78,8 +85,23 @@ public class ProjectModule extends BaseHandler implements ProjectService { @@ -78,8 +85,23 @@ public class ProjectModule extends BaseHandler implements ProjectService {
}
}
private boolean getProject(HttpExchange ex, long projectId, UmbrellaUser user) throws IOException, UmbrellaException {
var project = projects.load(projectId);
var map = project.toMap();
var members = new HashMap<Long,Map<String,Object>>();
for (var member : project.members()){
var perm = member.permission().name();
var userId = member.userId();
members.put(userId,Map.of(USER,users.loadUser(userId).toMap(),PERMISSION,perm));
}
if (!members.isEmpty()) map.put(MEMBERS,members);
return sendContent(ex,map);
}
public Collection<Project> listCompanyProjects(long companyId, boolean includeClosed) throws UmbrellaException {
return projects.ofCompany(companyId, includeClosed, users).values().stream().sorted(comparing(Project::name)).toList();
return projects.ofCompany(companyId, includeClosed).values().stream().sorted(comparing(Project::name)).toList();
}
private boolean listCompanyProjects(HttpExchange ex, UmbrellaUser user) throws IOException, UmbrellaException {
@ -97,12 +119,26 @@ public class ProjectModule extends BaseHandler implements ProjectService { @@ -97,12 +119,26 @@ public class ProjectModule extends BaseHandler implements ProjectService {
@Override
public Map<Long, Project> listUserProjects(long userId, boolean includeClosed) throws UmbrellaException {
return projects.ofUser(userId, includeClosed, users);
return projects.ofUser(userId, includeClosed);
}
private boolean listUserProjects(HttpExchange ex, UmbrellaUser user) throws IOException, UmbrellaException {
var projects = new HashMap<Long,Map<String,Object>>();
for (var entry : listUserProjects(user.id(),false).entrySet()) projects.put(entry.getKey(),entry.getValue().toMap());
for (var entry : listUserProjects(user.id(),false).entrySet()) {
var project = entry.getValue();
var map = project.toMap();
var members = new HashMap<Long,Map<String,Object>>();
var userMap = new HashMap<Long,UmbrellaUser>();
for (var member : project.members()){
var perm = member.permission().name();
var userId = member.userId();
var u = userMap.get(userId);
if (u == null) userMap.put(userId,u = users.loadUser(userId));
members.put(userId,Map.of(USER,u.toMap(),PERMISSION,perm));
}
if (!members.isEmpty()) map.put(MEMBERS,members);
projects.put(entry.getKey(),map);
}
return sendContent(ex,projects);
}
@ -120,7 +156,7 @@ public class ProjectModule extends BaseHandler implements ProjectService { @@ -120,7 +156,7 @@ public class ProjectModule extends BaseHandler implements ProjectService {
if (json.has(SETTINGS) && json.get(SETTINGS) instanceof JSONObject settingsJson){
showClosed = settingsJson.has(SHOW_CLOSED) && settingsJson.get(SHOW_CLOSED) == TRUE;
}
var prj = new Project(0,name,description,Project.Status.Open,companyId,showClosed, List.of(new Member(user, OWNER)));
var prj = new Project(0,name,description,Project.Status.Open,companyId,showClosed, List.of(new Member(user.id(), OWNER)));
prj = projects.save(prj);
return sendContent(ex,prj);
}

45
project/src/main/java/de/srsoftware/umbrella/project/SqliteDb.java

@ -14,7 +14,6 @@ import static java.lang.System.Logger.Level.INFO; @@ -14,7 +14,6 @@ import static java.lang.System.Logger.Level.INFO;
import static java.text.MessageFormat.format;
import de.srsoftware.tools.jdbc.Query;
import de.srsoftware.umbrella.core.api.UserService;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Member;
import de.srsoftware.umbrella.core.model.Permission;
@ -23,6 +22,7 @@ import java.sql.Connection; @@ -23,6 +22,7 @@ import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
public class SqliteDb implements ProjectDb {
private static final System.Logger LOG = System.getLogger("Sqlite4Project");
@ -35,29 +35,16 @@ public class SqliteDb implements ProjectDb { @@ -35,29 +35,16 @@ public class SqliteDb implements ProjectDb {
init();
}
private HashMap<Long, Project> addMembers(HashMap<Long, Project> projects, UserService userService) throws SQLException, UmbrellaException {
private Map<Long, Project> addMembers(Map<Long, Project> projects) throws SQLException, UmbrellaException {
Object[] ids = projects.keySet().toArray();
var rs = select("*").from(TABLE_PROJECT_USERS).where(PROJECT_ID,in(ids)).exec(db);
var userIdMap = new HashMap<Long,HashMap<Long, Permission>>();
while (rs.next()){
var userId = rs.getLong(USER_ID);
var projectId = rs.getLong(PROJECT_ID);
var permission = Permission.of(rs.getInt(PERMISSIONS));
HashMap<Long, Permission> userMap = userIdMap.computeIfAbsent(userId, k -> new HashMap<>());
userMap.put(projectId,permission);
projects.get(projectId).members().add(new Member(userId,permission));
}
rs.close();
var userMap = userService.list(userIdMap.keySet());
for (var entry : userIdMap.entrySet()){
var userId = entry.getKey();
var user = userMap.get(userId);
for (var inner : entry.getValue().entrySet()){
var projectId = inner.getKey();
var perm = inner.getValue();
var project = projects.get(projectId);
project.members().add(new Member(user,perm));
}
}
return projects;
}
@ -147,7 +134,22 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) @@ -147,7 +134,22 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
}
@Override
public HashMap<Long, Project> ofCompany(long companyId, boolean includeClosed, UserService userService) throws UmbrellaException {
public Project load(long projectId) throws UmbrellaException {
try {
var rs = select("*").from(TABLE_PROJECTS).where(ID, equal(projectId)).exec(db);
Project result = null;
if (rs.next()) result = Project.of(rs);
rs.close();
if (result == null) throw UmbrellaException.notFound("No project found for id {0}",projectId);
addMembers(Map.of(projectId,result));
return result;
} catch (SQLException e) {
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to load items from database");
}
}
@Override
public Map<Long, Project> ofCompany(long companyId, boolean includeClosed) throws UmbrellaException {
try {
var projects = new HashMap<Long,Project>();
var query = select("*").from(TABLE_PROJECTS).where(COMPANY_ID, equal(companyId));
@ -158,7 +160,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) @@ -158,7 +160,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
projects.put(project.id(),project);
}
rs.close();
return addMembers(projects,userService);
return addMembers(projects);
} catch (SQLException e) {
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to load items from database");
}
@ -167,7 +169,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) @@ -167,7 +169,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
@Override
public HashMap<Long, Project> ofUser(long userId, boolean includeClosed, UserService userService) throws UmbrellaException {
public Map<Long, Project> ofUser(long userId, boolean includeClosed) throws UmbrellaException {
try {
var projects = new HashMap<Long,Project>();
var query = select("*").from(TABLE_PROJECTS).leftJoin(ID,TABLE_PROJECT_USERS,PROJECT_ID).where(USER_ID, equal(userId));
@ -178,7 +180,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) @@ -178,7 +180,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
projects.put(project.id(),project);
}
rs.close();
return addMembers(projects,userService);
return addMembers(projects);
} catch (SQLException e) {
throw new UmbrellaException(HTTP_SERVER_ERROR,"Failed to load items from database");
}
@ -195,8 +197,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255) @@ -195,8 +197,7 @@ CREATE TABLE IF NOT EXISTS {0} ( {1} VARCHAR(255) PRIMARY KEY, {2} VARCHAR(255)
if (id != null){
if (!prj.members().isEmpty()) {
var query = insertInto(TABLE_PROJECT_USERS, PROJECT_ID, USER_ID, PERMISSIONS);
for (var member : prj.members())
query.values(id, member.user().id(), member.permission().code());
for (var member : prj.members()) query.values(id, member.userId(), member.permission().code());
query.execute(db).close();
}
return new Project(id, prj.name(), prj.description(),prj.status(),prj.companyId(),prj.showClosed(),prj.members());

31
translations/src/main/resources/de.json

@ -21,9 +21,11 @@ @@ -21,9 +21,11 @@
"confirm_deletion": "Soll '{pos}' wirklich gelöscht werden?",
"company": "Firma",
"company_optional": "Firma (optional)",
"confirmation": "Bestätigung",
"contact": "Kontakte",
"contained_tax": "enthaltene Steuer",
"content": "Inhalt",
"context": "Kontext",
"create": "anlegen",
"create_new_document": "neues Dokument",
"create_new_project": "neues Projekt anlegen",
@ -35,6 +37,7 @@ @@ -35,6 +37,7 @@
"customer_email": "Emailadresse des Kunden",
"customer": "Kunde",
"customer_id": "Kundennummer",
"data_sent": "Daten übermittelt",
"date": "Datum",
"delete": "löschen",
@ -95,6 +98,24 @@ @@ -95,6 +98,24 @@
"message": "Nachricht",
"messages": "Benachrichtigungen",
"model": "Modelle",
"module": {
"bookmark": "Lesezeichen",
"commons": " ",
"company": "Firma",
"contact": "Kontakte",
"document": "Dokumente",
"files": "Dateien",
"items": "Artikel",
"message": "Nachrichten",
"model": "Modelle",
"notes": "Notizen",
"project": "Projekte",
"stock": "Inventar",
"task": "Aufgaben",
"time": "Zeiterfassung",
"user": "Benutzer",
"wiki": "Wiki"
},
"mismatch": "ungleich",
"must_not_be_empty": "darf nicht leer sein",
@ -111,13 +132,18 @@ @@ -111,13 +132,18 @@
"old_password": "altes Passwort",
"password" : "Passwort",
"permission": {
"EDIT": "lesen/schreiben",
"OWNER": "Besitzer"
},
"permissions": "Berechtigungen",
"pos": "Pos",
"position": "Position",
"positions": "Positionen",
"price": "Preis",
"processing_code": "Code wird verarbeitet…",
"project": "Projekte",
"project": "Projekt",
"projects": "Projekte",
"repeat_new_password": "Wiederholung",
"results": "Ergebnisse",
@ -153,7 +179,8 @@ @@ -153,7 +179,8 @@
"stock": "Inventar",
"subject": "Betreff",
"task": "Aufgaben",
"task": "Aufgabe",
"tasks": "Aufgaben",
"tax_id": "Steuernummer",
"tax_rate": "Steuersatz",
"theme": "Design",

2
user/src/main/java/de/srsoftware/umbrella/user/UserModule.java

@ -16,8 +16,8 @@ import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; @@ -16,8 +16,8 @@ import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*;
import static de.srsoftware.umbrella.user.Constants.*;
import static de.srsoftware.umbrella.user.Paths.*;
import static de.srsoftware.umbrella.user.Paths.IMPERSONATE;
import static de.srsoftware.umbrella.user.model.DbUser.Permission.*;
import static de.srsoftware.umbrella.user.model.DbUser.Permission;
import static de.srsoftware.umbrella.user.model.DbUser.Permission.*;
import static java.lang.System.Logger.Level.*;
import static java.net.HttpURLConnection.*;
import static java.nio.charset.StandardCharsets.UTF_8;

Loading…
Cancel
Save