From ebe0cf7c5796f0920a5e8094450eaa8853789769 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Fri, 8 Aug 2025 23:33:04 +0200 Subject: [PATCH] implemented editing members of company --- .../umbrella/company/CompanyModule.java | 29 ++++++++++-- .../srsoftware/umbrella/company/SqliteDb.java | 12 ++++- .../umbrella/company/api/CompanyDb.java | 2 + .../umbrella/core/model/Company.java | 1 - frontend/src/routes/company/Editor.svelte | 47 ++++++++++++++++++- translations/src/main/resources/de.json | 5 +- 6 files changed, 83 insertions(+), 13 deletions(-) diff --git a/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java b/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java index 64ce783..113a76a 100644 --- a/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java +++ b/company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java @@ -3,8 +3,8 @@ package de.srsoftware.umbrella.company; import static de.srsoftware.umbrella.company.Constants.CONFIG_DATABASE; import static de.srsoftware.umbrella.core.ConnectionProvider.connect; -import static de.srsoftware.umbrella.core.Constants.COMPANY; import static de.srsoftware.umbrella.core.Constants.ID; +import static de.srsoftware.umbrella.core.Constants.MEMBERS; import static de.srsoftware.umbrella.core.Paths.LIST; import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; @@ -18,7 +18,6 @@ import de.srsoftware.umbrella.core.api.CompanyService; import de.srsoftware.umbrella.core.api.UserService; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.*; - import java.io.IOException; import java.util.*; @@ -61,7 +60,7 @@ public class CompanyModule extends BaseHandler implements CompanyService { var head = path.pop(); return switch (head) { case null -> super.doGet(path, ex); - default -> patchProject(Long.parseLong(head), user.get(), ex); + default -> patchCompany(Long.parseLong(head), user.get(), ex); }; } catch (NumberFormatException n) { return send(ex,invalidFieldException(ID,"ID (Long)")); @@ -133,11 +132,31 @@ public class CompanyModule extends BaseHandler implements CompanyService { return companyDb.getMembers(companyId).contains(userId); } - private boolean patchProject(long companyId, UmbrellaUser user, HttpExchange ex) throws IOException { + private boolean patchCompany(long companyId, UmbrellaUser user, HttpExchange ex) throws IOException { var company = get(companyId); if (!membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name()); + var json = json(ex); - return sendContent(ex,companyDb.save(company.patch(json))); + company = companyDb.save(company.patch(json)); + if (json.has(MEMBERS)){ + var wantedMembers = new HashSet(); + wantedMembers.add(user.id()); // user may not delete itself + for (var o : json.getJSONArray(MEMBERS).toList()){ + if (o instanceof Number uid) wantedMembers.add(uid.longValue()); + } + loadMembers(List.of(company)); // load current members + var currentMembers = company.members().keySet(); + for (var currentMember : currentMembers){ + if (!wantedMembers.contains(currentMember)) companyDb.dropUser(companyId,currentMember); + } + for (var wantedMember : wantedMembers){ + if (!currentMembers.contains(wantedMember)) companyDb.addUser(companyId,wantedMember); + } + company.members().clear(); + loadMembers(List.of(company)); // load new members + } + + return sendContent(ex,company); } private boolean postNewCompany(UmbrellaUser user, HttpExchange ex) throws IOException { diff --git a/company/src/main/java/de/srsoftware/umbrella/company/SqliteDb.java b/company/src/main/java/de/srsoftware/umbrella/company/SqliteDb.java index 29e6d56..a313d85 100644 --- a/company/src/main/java/de/srsoftware/umbrella/company/SqliteDb.java +++ b/company/src/main/java/de/srsoftware/umbrella/company/SqliteDb.java @@ -13,14 +13,13 @@ import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.databaseE import de.srsoftware.umbrella.company.api.CompanyDb; import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.model.Company; -import org.json.JSONObject; - import java.sql.Connection; import java.sql.SQLException; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; +import org.json.JSONObject; public class SqliteDb implements CompanyDb { @@ -43,6 +42,15 @@ public class SqliteDb implements CompanyDb { } } + @Override + public void dropUser(long company_id, long user_id) { + try { + delete().from(TABLE_COMPANIES_USERS).where(COMPANY_ID,equal(company_id)).where(USER_ID,equal(user_id)).execute(db); + } catch (SQLException e) { + throw databaseException("Failed to assign user {0} to company {1}"); + } + } + @Override public Collection getMembers(long companyId) throws UmbrellaException { try { diff --git a/company/src/main/java/de/srsoftware/umbrella/company/api/CompanyDb.java b/company/src/main/java/de/srsoftware/umbrella/company/api/CompanyDb.java index 2b672a5..6426145 100644 --- a/company/src/main/java/de/srsoftware/umbrella/company/api/CompanyDb.java +++ b/company/src/main/java/de/srsoftware/umbrella/company/api/CompanyDb.java @@ -9,6 +9,8 @@ import java.util.Map; public interface CompanyDb { void addUser(long company_id, long user_id); + void dropUser(long company_id, long user_id); + Collection getMembers(long companyId) throws UmbrellaException; Map listCompaniesOf(long id) throws UmbrellaException; diff --git a/core/src/main/java/de/srsoftware/umbrella/core/model/Company.java b/core/src/main/java/de/srsoftware/umbrella/core/model/Company.java index 2e5af97..3d71d94 100644 --- a/core/src/main/java/de/srsoftware/umbrella/core/model/Company.java +++ b/core/src/main/java/de/srsoftware/umbrella/core/model/Company.java @@ -10,7 +10,6 @@ import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; - import org.json.JSONException; import org.json.JSONObject; diff --git a/frontend/src/routes/company/Editor.svelte b/frontend/src/routes/company/Editor.svelte index 0d05c2d..1446282 100644 --- a/frontend/src/routes/company/Editor.svelte +++ b/frontend/src/routes/company/Editor.svelte @@ -3,6 +3,32 @@ import {t} from '../../translations.svelte.js'; import LineEditor from '../../Components/LineEditor.svelte'; import Multiline from '../../Components/MultilineEditor.svelte'; + import Users from '../../Components/UserSelector.svelte' + + let caption = $state(t('save_object',{object:t('users')})); + let { company } = $props(); + let error = $state(null); + let btnEnabled = $state(true); + let memberCopy = $state(JSON.parse(JSON.stringify(company.members))); + + async function getCandidates(text){ + const url = api('user/search'); + const resp = await fetch(url,{ + credentials : 'include', + method : 'POST', + body : text + }); + if (resp.ok){ + error = null; + const input = await resp.json(); + return Object.fromEntries( + Object.entries(input).map(([key, value]) => [key, value.name]) + ); + } else { + error = await resp.text(); + return {}; + } + } async function patch(changeSet){ const url = api(`company/${company.id}`) @@ -12,13 +38,27 @@ body : JSON.stringify(changeSet) }); if (resp.ok){ + const patched = await resp.json(); + for (let key of Object.keys(patched)){ + console.log('patching '+key+'…'); + company[key] = patched[key]; + } return true; } error = await resp.text(); return false; } - let { company } = $props(); + async function saveUsers(){ + btnEnabled = false; + caption = t('data_sent'); + const members = Object.keys(memberCopy).map(Number); + company.members = {}; + var success = await patch({members:members}); + if (success) caption = t('saved'); + btnEnabled = true; + } +
@@ -60,5 +100,10 @@ {t('customer_number_prefix')} patch({customer_number_prefix:val})} />
+
+ {t('members')} + + +
{/if} \ No newline at end of file diff --git a/translations/src/main/resources/de.json b/translations/src/main/resources/de.json index 8fe0405..60ec5d8 100644 --- a/translations/src/main/resources/de.json +++ b/translations/src/main/resources/de.json @@ -176,10 +176,7 @@ "save": "speichern", "saved": "gespeichert", - "save_note": "Notiz speichern", - "save_service": "Service speichern", - "save_task": "Aufgabe speichern", - "save_user": "Nutzer speichern", + "save_object": "{object} speichern", "search": "Suche", "select_company" : "Wählen Sie eine ihrer Firmen:", "select_customer": "Kunde auswählen",