Browse Source

implemented editing members of company

featue/module_registry
Stephan Richter 3 months ago
parent
commit
ebe0cf7c57
  1. 29
      company/src/main/java/de/srsoftware/umbrella/company/CompanyModule.java
  2. 12
      company/src/main/java/de/srsoftware/umbrella/company/SqliteDb.java
  3. 2
      company/src/main/java/de/srsoftware/umbrella/company/api/CompanyDb.java
  4. 1
      core/src/main/java/de/srsoftware/umbrella/core/model/Company.java
  5. 47
      frontend/src/routes/company/Editor.svelte
  6. 5
      translations/src/main/resources/de.json

29
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.company.Constants.CONFIG_DATABASE;
import static de.srsoftware.umbrella.core.ConnectionProvider.connect; 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.ID;
import static de.srsoftware.umbrella.core.Constants.MEMBERS;
import static de.srsoftware.umbrella.core.Paths.LIST; import static de.srsoftware.umbrella.core.Paths.LIST;
import static de.srsoftware.umbrella.core.exceptions.UmbrellaException.*; 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.api.UserService;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.*; import de.srsoftware.umbrella.core.model.*;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
@ -61,7 +60,7 @@ public class CompanyModule extends BaseHandler implements CompanyService {
var head = path.pop(); var head = path.pop();
return switch (head) { return switch (head) {
case null -> super.doGet(path, ex); 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) { } catch (NumberFormatException n) {
return send(ex,invalidFieldException(ID,"ID (Long)")); return send(ex,invalidFieldException(ID,"ID (Long)"));
@ -133,11 +132,31 @@ public class CompanyModule extends BaseHandler implements CompanyService {
return companyDb.getMembers(companyId).contains(userId); 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); var company = get(companyId);
if (!membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name()); if (!membership(companyId,user.id())) throw forbidden("You are mot a member of company {0}",company.name());
var json = json(ex); 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<Long>();
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 { private boolean postNewCompany(UmbrellaUser user, HttpExchange ex) throws IOException {

12
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.company.api.CompanyDb;
import de.srsoftware.umbrella.core.exceptions.UmbrellaException; import de.srsoftware.umbrella.core.exceptions.UmbrellaException;
import de.srsoftware.umbrella.core.model.Company; import de.srsoftware.umbrella.core.model.Company;
import org.json.JSONObject;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import org.json.JSONObject;
public class SqliteDb implements CompanyDb { 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 @Override
public Collection<Long> getMembers(long companyId) throws UmbrellaException { public Collection<Long> getMembers(long companyId) throws UmbrellaException {
try { try {

2
company/src/main/java/de/srsoftware/umbrella/company/api/CompanyDb.java

@ -9,6 +9,8 @@ import java.util.Map;
public interface CompanyDb { public interface CompanyDb {
void addUser(long company_id, long user_id); void addUser(long company_id, long user_id);
void dropUser(long company_id, long user_id);
Collection<Long> getMembers(long companyId) throws UmbrellaException; Collection<Long> getMembers(long companyId) throws UmbrellaException;
Map<Long,Company> listCompaniesOf(long id) throws UmbrellaException; Map<Long,Company> listCompaniesOf(long id) throws UmbrellaException;

1
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.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;

47
frontend/src/routes/company/Editor.svelte

@ -3,6 +3,32 @@
import {t} from '../../translations.svelte.js'; import {t} from '../../translations.svelte.js';
import LineEditor from '../../Components/LineEditor.svelte'; import LineEditor from '../../Components/LineEditor.svelte';
import Multiline from '../../Components/MultilineEditor.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){ async function patch(changeSet){
const url = api(`company/${company.id}`) const url = api(`company/${company.id}`)
@ -12,13 +38,27 @@
body : JSON.stringify(changeSet) body : JSON.stringify(changeSet)
}); });
if (resp.ok){ 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; return true;
} }
error = await resp.text(); error = await resp.text();
return false; 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;
}
</script> </script>
<fieldset> <fieldset>
@ -60,5 +100,10 @@
<legend>{t('customer_number_prefix')}</legend> <legend>{t('customer_number_prefix')}</legend>
<LineEditor bind:value={company.customer_number_prefix} editable={true} onSet={val => patch({customer_number_prefix:val})} /> <LineEditor bind:value={company.customer_number_prefix} editable={true} onSet={val => patch({customer_number_prefix:val})} />
</fieldset> </fieldset>
<fieldset>
<legend>{t('members')}</legend>
<Users bind:users={memberCopy} {getCandidates} />
<button onclick={saveUsers} disabled={!btnEnabled} >{caption}</button>
</fieldset>
{/if} {/if}
</fieldset> </fieldset>

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

@ -176,10 +176,7 @@
"save": "speichern", "save": "speichern",
"saved": "gespeichert", "saved": "gespeichert",
"save_note": "Notiz speichern", "save_object": "{object} speichern",
"save_service": "Service speichern",
"save_task": "Aufgabe speichern",
"save_user": "Nutzer speichern",
"search": "Suche", "search": "Suche",
"select_company" : "Wählen Sie eine ihrer Firmen:", "select_company" : "Wählen Sie eine ihrer Firmen:",
"select_customer": "Kunde auswählen", "select_customer": "Kunde auswählen",

Loading…
Cancel
Save