feat: isolate catalog data per primary user (accountId)
- Add accountId to Farmer, MedicationCatalogItem, PathogenCatalogItem, AntibioticCatalogItem - Create new /api/catalog endpoints for CUSTOMER role only - Remove DemoDataInitializer (no more demo data generation) - Add DefaultUserInitializer for admin user creation only - Update repositories with accountId-based query methods - Update CatalogService with accountId isolation and role-based access - Update SecurityConfig: /api/catalog/** for CUSTOMER, /api/admin/** for ADMIN - Update frontend AdministrationPage to use new /api/catalog endpoints - Migrate existing data without accountId to first admin user
This commit is contained in:
@@ -107,6 +107,7 @@ Kundenregistrierung:
|
|||||||
- `cd frontend && npm run build`
|
- `cd frontend && npm run build`
|
||||||
|
|
||||||
## Docker
|
## Docker
|
||||||
|
docker build -t muh:0.9.1 .
|
||||||
docker buildx build --platform linux/amd64 -t gitea.appcreation.de/sven/muh:0.8.0 --push .
|
docker buildx build --platform linux/amd64 -t gitea.appcreation.de/sven/muh:0.8.0 --push .
|
||||||
|
|
||||||
docker run -d --name muh --network br0 --ip 192.168.180.26 --restart unless-stopped -e MUH_MONGODB_URL=mongodb://192.168.180.25:27017/muh -e MUH_TOKEN_SECRET=local-dev-muh-token-secret-2026-03-13 -e MUH_TOKEN_VALIDITY_HOURS=12 -e MUH_ALLOWED_ORIGINS=https://muh.appcreation.de gitea.appcreation.de/sven/muh:0.8.0
|
docker run -d --name muh --network br0 --ip 192.168.180.26 --restart unless-stopped -e MUH_MONGODB_URL=mongodb://192.168.180.25:27017/muh -e MUH_TOKEN_SECRET=local-dev-muh-token-secret-2026-03-13 -e MUH_TOKEN_VALIDITY_HOURS=12 -e MUH_ALLOWED_ORIGINS=https://muh.appcreation.de gitea.appcreation.de/sven/muh:0.8.0
|
||||||
@@ -8,6 +8,7 @@ import java.time.LocalDateTime;
|
|||||||
@Document("antibiotics")
|
@Document("antibiotics")
|
||||||
public record AntibioticCatalogItem(
|
public record AntibioticCatalogItem(
|
||||||
@Id String id,
|
@Id String id,
|
||||||
|
String accountId,
|
||||||
String businessKey,
|
String businessKey,
|
||||||
String code,
|
String code,
|
||||||
String name,
|
String name,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.time.LocalDateTime;
|
|||||||
@Document("farmers")
|
@Document("farmers")
|
||||||
public record Farmer(
|
public record Farmer(
|
||||||
@Id String id,
|
@Id String id,
|
||||||
|
String accountId,
|
||||||
String businessKey,
|
String businessKey,
|
||||||
String name,
|
String name,
|
||||||
String email,
|
String email,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.time.LocalDateTime;
|
|||||||
@Document("medications")
|
@Document("medications")
|
||||||
public record MedicationCatalogItem(
|
public record MedicationCatalogItem(
|
||||||
@Id String id,
|
@Id String id,
|
||||||
|
String accountId,
|
||||||
String businessKey,
|
String businessKey,
|
||||||
String name,
|
String name,
|
||||||
MedicationCategory category,
|
MedicationCategory category,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import java.time.LocalDateTime;
|
|||||||
@Document("pathogens")
|
@Document("pathogens")
|
||||||
public record PathogenCatalogItem(
|
public record PathogenCatalogItem(
|
||||||
@Id String id,
|
@Id String id,
|
||||||
|
String accountId,
|
||||||
String businessKey,
|
String businessKey,
|
||||||
String code,
|
String code,
|
||||||
String name,
|
String name,
|
||||||
|
|||||||
@@ -7,4 +7,8 @@ import java.util.List;
|
|||||||
|
|
||||||
public interface AntibioticCatalogRepository extends MongoRepository<AntibioticCatalogItem, String> {
|
public interface AntibioticCatalogRepository extends MongoRepository<AntibioticCatalogItem, String> {
|
||||||
List<AntibioticCatalogItem> findByActiveTrueOrderByNameAsc();
|
List<AntibioticCatalogItem> findByActiveTrueOrderByNameAsc();
|
||||||
|
|
||||||
|
List<AntibioticCatalogItem> findByAccountIdOrderByNameAsc(String accountId);
|
||||||
|
|
||||||
|
List<AntibioticCatalogItem> findByAccountIdAndActiveTrueOrderByNameAsc(String accountId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,5 +8,9 @@ import java.util.List;
|
|||||||
public interface FarmerRepository extends MongoRepository<Farmer, String> {
|
public interface FarmerRepository extends MongoRepository<Farmer, String> {
|
||||||
List<Farmer> findByActiveTrueOrderByNameAsc();
|
List<Farmer> findByActiveTrueOrderByNameAsc();
|
||||||
|
|
||||||
|
List<Farmer> findByAccountIdOrderByNameAsc(String accountId);
|
||||||
|
|
||||||
|
List<Farmer> findByAccountIdAndActiveTrueOrderByNameAsc(String accountId);
|
||||||
|
|
||||||
List<Farmer> findByNameContainingIgnoreCaseOrderByNameAsc(String name);
|
List<Farmer> findByNameContainingIgnoreCaseOrderByNameAsc(String name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,4 +7,8 @@ import java.util.List;
|
|||||||
|
|
||||||
public interface MedicationCatalogRepository extends MongoRepository<MedicationCatalogItem, String> {
|
public interface MedicationCatalogRepository extends MongoRepository<MedicationCatalogItem, String> {
|
||||||
List<MedicationCatalogItem> findByActiveTrueOrderByNameAsc();
|
List<MedicationCatalogItem> findByActiveTrueOrderByNameAsc();
|
||||||
|
|
||||||
|
List<MedicationCatalogItem> findByAccountIdOrderByNameAsc(String accountId);
|
||||||
|
|
||||||
|
List<MedicationCatalogItem> findByAccountIdAndActiveTrueOrderByNameAsc(String accountId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,4 +7,8 @@ import java.util.List;
|
|||||||
|
|
||||||
public interface PathogenCatalogRepository extends MongoRepository<PathogenCatalogItem, String> {
|
public interface PathogenCatalogRepository extends MongoRepository<PathogenCatalogItem, String> {
|
||||||
List<PathogenCatalogItem> findByActiveTrueOrderByNameAsc();
|
List<PathogenCatalogItem> findByActiveTrueOrderByNameAsc();
|
||||||
|
|
||||||
|
List<PathogenCatalogItem> findByAccountIdOrderByNameAsc(String accountId);
|
||||||
|
|
||||||
|
List<PathogenCatalogItem> findByAccountIdAndActiveTrueOrderByNameAsc(String accountId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ public class SecurityConfig {
|
|||||||
.sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
.sessionManagement(configurer -> configurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
|
||||||
.authorizeHttpRequests(authorize -> authorize
|
.authorizeHttpRequests(authorize -> authorize
|
||||||
.requestMatchers(HttpMethod.POST, "/api/session/password-login", "/api/session/register").permitAll()
|
.requestMatchers(HttpMethod.POST, "/api/session/password-login", "/api/session/register").permitAll()
|
||||||
|
.requestMatchers("/api/catalog/**").hasRole("CUSTOMER")
|
||||||
.requestMatchers("/api/admin/**").hasRole("ADMIN")
|
.requestMatchers("/api/admin/**").hasRole("ADMIN")
|
||||||
.requestMatchers("/api/**").authenticated()
|
.requestMatchers("/api/**").authenticated()
|
||||||
.anyRequest().permitAll()
|
.anyRequest().permitAll()
|
||||||
|
|||||||
@@ -90,51 +90,75 @@ public class CatalogService {
|
|||||||
this.authorizationService = authorizationService;
|
this.authorizationService = authorizationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActiveCatalogSummary activeCatalogSummary() {
|
public ActiveCatalogSummary activeCatalogSummary(String actorId) {
|
||||||
|
AppUser actor = requireActiveActor(actorId, "Nicht berechtigt");
|
||||||
return new ActiveCatalogSummary(
|
return new ActiveCatalogSummary(
|
||||||
farmerRepository.findByActiveTrueOrderByNameAsc().stream().map(this::toFarmerOption).toList(),
|
listActiveFarmersForActor(actor).stream().map(this::toFarmerOption).toList(),
|
||||||
medicationRepository.findByActiveTrueOrderByNameAsc().stream().map(this::toMedicationOption).toList(),
|
listActiveMedicationsForActor(actor).stream().map(this::toMedicationOption).toList(),
|
||||||
pathogenRepository.findByActiveTrueOrderByNameAsc().stream().map(this::toPathogenOption).toList(),
|
listActivePathogensForActor(actor).stream().map(this::toPathogenOption).toList(),
|
||||||
antibioticRepository.findByActiveTrueOrderByNameAsc().stream().map(this::toAntibioticOption).toList(),
|
listActiveAntibioticsForActor(actor).stream().map(this::toAntibioticOption).toList(),
|
||||||
List.of()
|
List.of()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AdministrationOverview administrationOverview(String actorId) {
|
public AdministrationOverview administrationOverview(String actorId) {
|
||||||
authorizationService.requireActiveUser(actorId, "Nicht berechtigt");
|
AppUser actor = requireActiveActor(actorId, "Nicht berechtigt");
|
||||||
return new AdministrationOverview(listFarmerRows(), listMedicationRows(), listPathogenRows(), listAntibioticRows());
|
return new AdministrationOverview(
|
||||||
|
listFarmerRowsForActor(actor),
|
||||||
|
listMedicationRowsForActor(actor),
|
||||||
|
listPathogenRowsForActor(actor),
|
||||||
|
listAntibioticRowsForActor(actor)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FarmerRow> listFarmerRows() {
|
// Hilfsmethoden für Datenzugriff (immer nur eigene Daten des Hauptbenutzers)
|
||||||
return farmerRepository.findAll().stream()
|
private List<Farmer> listActiveFarmersForActor(AppUser actor) {
|
||||||
|
return farmerRepository.findByAccountIdAndActiveTrueOrderByNameAsc(resolveAccountId(actor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MedicationCatalogItem> listActiveMedicationsForActor(AppUser actor) {
|
||||||
|
return medicationRepository.findByAccountIdAndActiveTrueOrderByNameAsc(resolveAccountId(actor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<PathogenCatalogItem> listActivePathogensForActor(AppUser actor) {
|
||||||
|
return pathogenRepository.findByAccountIdAndActiveTrueOrderByNameAsc(resolveAccountId(actor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<AntibioticCatalogItem> listActiveAntibioticsForActor(AppUser actor) {
|
||||||
|
return antibioticRepository.findByAccountIdAndActiveTrueOrderByNameAsc(resolveAccountId(actor));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FarmerRow> listFarmerRowsForActor(AppUser actor) {
|
||||||
|
return farmerRepository.findByAccountIdOrderByNameAsc(resolveAccountId(actor)).stream()
|
||||||
.map(this::toFarmerRow)
|
.map(this::toFarmerRow)
|
||||||
.sorted(FARMER_ROW_COMPARATOR)
|
.sorted(FARMER_ROW_COMPARATOR)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MedicationRow> listMedicationRows() {
|
private List<MedicationRow> listMedicationRowsForActor(AppUser actor) {
|
||||||
return medicationRepository.findAll().stream()
|
return medicationRepository.findByAccountIdOrderByNameAsc(resolveAccountId(actor)).stream()
|
||||||
.map(this::toMedicationRow)
|
.map(this::toMedicationRow)
|
||||||
.sorted(MEDICATION_ROW_COMPARATOR)
|
.sorted(MEDICATION_ROW_COMPARATOR)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PathogenRow> listPathogenRows() {
|
private List<PathogenRow> listPathogenRowsForActor(AppUser actor) {
|
||||||
return pathogenRepository.findAll().stream()
|
return pathogenRepository.findByAccountIdOrderByNameAsc(resolveAccountId(actor)).stream()
|
||||||
.map(this::toPathogenRow)
|
.map(this::toPathogenRow)
|
||||||
.sorted(PATHOGEN_ROW_COMPARATOR)
|
.sorted(PATHOGEN_ROW_COMPARATOR)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AntibioticRow> listAntibioticRows() {
|
private List<AntibioticRow> listAntibioticRowsForActor(AppUser actor) {
|
||||||
return antibioticRepository.findAll().stream()
|
return antibioticRepository.findByAccountIdOrderByNameAsc(resolveAccountId(actor)).stream()
|
||||||
.map(this::toAntibioticRow)
|
.map(this::toAntibioticRow)
|
||||||
.sorted(ANTIBIOTIC_ROW_COMPARATOR)
|
.sorted(ANTIBIOTIC_ROW_COMPARATOR)
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<FarmerRow> saveFarmers(String actorId, List<FarmerMutation> mutations) {
|
public List<FarmerRow> saveFarmers(String actorId, List<FarmerMutation> mutations) {
|
||||||
authorizationService.requireActiveUser(actorId, "Nicht berechtigt");
|
AppUser actor = requireActiveActor(actorId, "Nicht berechtigt");
|
||||||
|
String accountId = resolveAccountId(actor);
|
||||||
for (FarmerMutation mutation : mutations) {
|
for (FarmerMutation mutation : mutations) {
|
||||||
if (isBlank(mutation.name())) {
|
if (isBlank(mutation.name())) {
|
||||||
continue;
|
continue;
|
||||||
@@ -143,6 +167,7 @@ public class CatalogService {
|
|||||||
if (isBlank(mutation.id())) {
|
if (isBlank(mutation.id())) {
|
||||||
farmerRepository.save(new Farmer(
|
farmerRepository.save(new Farmer(
|
||||||
null,
|
null,
|
||||||
|
accountId,
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
mutation.name().trim(),
|
mutation.name().trim(),
|
||||||
blankToNull(mutation.email()),
|
blankToNull(mutation.email()),
|
||||||
@@ -156,11 +181,16 @@ public class CatalogService {
|
|||||||
String mutationId = requireText(mutation.id(), "Landwirt-ID fehlt");
|
String mutationId = requireText(mutation.id(), "Landwirt-ID fehlt");
|
||||||
Farmer existing = farmerRepository.findById(mutationId)
|
Farmer existing = farmerRepository.findById(mutationId)
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Landwirt nicht gefunden"));
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Landwirt nicht gefunden"));
|
||||||
|
// Sicherstellen, dass der Benutzer nur seine eigenen Daten bearbeiten kann
|
||||||
|
if (!accountId.equals(existing.accountId())) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Nicht berechtigt");
|
||||||
|
}
|
||||||
boolean changed = !existing.name().equals(mutation.name().trim())
|
boolean changed = !existing.name().equals(mutation.name().trim())
|
||||||
|| !safeEquals(existing.email(), blankToNull(mutation.email()));
|
|| !safeEquals(existing.email(), blankToNull(mutation.email()));
|
||||||
if (changed) {
|
if (changed) {
|
||||||
farmerRepository.save(new Farmer(
|
farmerRepository.save(new Farmer(
|
||||||
existing.id(),
|
existing.id(),
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
existing.name(),
|
existing.name(),
|
||||||
existing.email(),
|
existing.email(),
|
||||||
@@ -171,6 +201,7 @@ public class CatalogService {
|
|||||||
));
|
));
|
||||||
farmerRepository.save(new Farmer(
|
farmerRepository.save(new Farmer(
|
||||||
null,
|
null,
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
mutation.name().trim(),
|
mutation.name().trim(),
|
||||||
blankToNull(mutation.email()),
|
blankToNull(mutation.email()),
|
||||||
@@ -184,6 +215,7 @@ public class CatalogService {
|
|||||||
if (existing.active() != mutation.active()) {
|
if (existing.active() != mutation.active()) {
|
||||||
farmerRepository.save(new Farmer(
|
farmerRepository.save(new Farmer(
|
||||||
existing.id(),
|
existing.id(),
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
existing.name(),
|
existing.name(),
|
||||||
existing.email(),
|
existing.email(),
|
||||||
@@ -194,11 +226,12 @@ public class CatalogService {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return listFarmerRows();
|
return listFarmerRowsForActor(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MedicationRow> saveMedications(String actorId, List<MedicationMutation> mutations) {
|
public List<MedicationRow> saveMedications(String actorId, List<MedicationMutation> mutations) {
|
||||||
authorizationService.requireActiveUser(actorId, "Nicht berechtigt");
|
AppUser actor = requireActiveActor(actorId, "Nicht berechtigt");
|
||||||
|
String accountId = resolveAccountId(actor);
|
||||||
for (MedicationMutation mutation : mutations) {
|
for (MedicationMutation mutation : mutations) {
|
||||||
if (isBlank(mutation.name()) || mutation.category() == null) {
|
if (isBlank(mutation.name()) || mutation.category() == null) {
|
||||||
continue;
|
continue;
|
||||||
@@ -207,6 +240,7 @@ public class CatalogService {
|
|||||||
if (isBlank(mutation.id())) {
|
if (isBlank(mutation.id())) {
|
||||||
medicationRepository.save(new MedicationCatalogItem(
|
medicationRepository.save(new MedicationCatalogItem(
|
||||||
null,
|
null,
|
||||||
|
accountId,
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
mutation.name().trim(),
|
mutation.name().trim(),
|
||||||
mutation.category(),
|
mutation.category(),
|
||||||
@@ -220,11 +254,16 @@ public class CatalogService {
|
|||||||
String mutationId = requireText(mutation.id(), "Medikament-ID fehlt");
|
String mutationId = requireText(mutation.id(), "Medikament-ID fehlt");
|
||||||
MedicationCatalogItem existing = medicationRepository.findById(mutationId)
|
MedicationCatalogItem existing = medicationRepository.findById(mutationId)
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Medikament nicht gefunden"));
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Medikament nicht gefunden"));
|
||||||
|
// Sicherstellen, dass der Benutzer nur seine eigenen Daten bearbeiten kann
|
||||||
|
if (!accountId.equals(existing.accountId())) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Nicht berechtigt");
|
||||||
|
}
|
||||||
boolean changed = !existing.name().equals(mutation.name().trim())
|
boolean changed = !existing.name().equals(mutation.name().trim())
|
||||||
|| existing.category() != mutation.category();
|
|| existing.category() != mutation.category();
|
||||||
if (changed) {
|
if (changed) {
|
||||||
medicationRepository.save(new MedicationCatalogItem(
|
medicationRepository.save(new MedicationCatalogItem(
|
||||||
existing.id(),
|
existing.id(),
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
existing.name(),
|
existing.name(),
|
||||||
existing.category(),
|
existing.category(),
|
||||||
@@ -235,6 +274,7 @@ public class CatalogService {
|
|||||||
));
|
));
|
||||||
medicationRepository.save(new MedicationCatalogItem(
|
medicationRepository.save(new MedicationCatalogItem(
|
||||||
null,
|
null,
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
mutation.name().trim(),
|
mutation.name().trim(),
|
||||||
mutation.category(),
|
mutation.category(),
|
||||||
@@ -248,6 +288,7 @@ public class CatalogService {
|
|||||||
if (existing.active() != mutation.active()) {
|
if (existing.active() != mutation.active()) {
|
||||||
medicationRepository.save(new MedicationCatalogItem(
|
medicationRepository.save(new MedicationCatalogItem(
|
||||||
existing.id(),
|
existing.id(),
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
existing.name(),
|
existing.name(),
|
||||||
existing.category(),
|
existing.category(),
|
||||||
@@ -258,11 +299,12 @@ public class CatalogService {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return listMedicationRows();
|
return listMedicationRowsForActor(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PathogenRow> savePathogens(String actorId, List<PathogenMutation> mutations) {
|
public List<PathogenRow> savePathogens(String actorId, List<PathogenMutation> mutations) {
|
||||||
authorizationService.requireActiveUser(actorId, "Nicht berechtigt");
|
AppUser actor = requireActiveActor(actorId, "Nicht berechtigt");
|
||||||
|
String accountId = resolveAccountId(actor);
|
||||||
for (PathogenMutation mutation : mutations) {
|
for (PathogenMutation mutation : mutations) {
|
||||||
if (isBlank(mutation.name()) || mutation.kind() == null) {
|
if (isBlank(mutation.name()) || mutation.kind() == null) {
|
||||||
continue;
|
continue;
|
||||||
@@ -271,6 +313,7 @@ public class CatalogService {
|
|||||||
if (isBlank(mutation.id())) {
|
if (isBlank(mutation.id())) {
|
||||||
pathogenRepository.save(new PathogenCatalogItem(
|
pathogenRepository.save(new PathogenCatalogItem(
|
||||||
null,
|
null,
|
||||||
|
accountId,
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
blankToNull(mutation.code()),
|
blankToNull(mutation.code()),
|
||||||
mutation.name().trim(),
|
mutation.name().trim(),
|
||||||
@@ -285,12 +328,17 @@ public class CatalogService {
|
|||||||
String mutationId = requireText(mutation.id(), "Erreger-ID fehlt");
|
String mutationId = requireText(mutation.id(), "Erreger-ID fehlt");
|
||||||
PathogenCatalogItem existing = pathogenRepository.findById(mutationId)
|
PathogenCatalogItem existing = pathogenRepository.findById(mutationId)
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Erreger nicht gefunden"));
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Erreger nicht gefunden"));
|
||||||
|
// Sicherstellen, dass der Benutzer nur seine eigenen Daten bearbeiten kann
|
||||||
|
if (!accountId.equals(existing.accountId())) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Nicht berechtigt");
|
||||||
|
}
|
||||||
boolean changed = !existing.name().equals(mutation.name().trim())
|
boolean changed = !existing.name().equals(mutation.name().trim())
|
||||||
|| !safeEquals(existing.code(), blankToNull(mutation.code()))
|
|| !safeEquals(existing.code(), blankToNull(mutation.code()))
|
||||||
|| existing.kind() != mutation.kind();
|
|| existing.kind() != mutation.kind();
|
||||||
if (changed) {
|
if (changed) {
|
||||||
pathogenRepository.save(new PathogenCatalogItem(
|
pathogenRepository.save(new PathogenCatalogItem(
|
||||||
existing.id(),
|
existing.id(),
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
existing.code(),
|
existing.code(),
|
||||||
existing.name(),
|
existing.name(),
|
||||||
@@ -302,6 +350,7 @@ public class CatalogService {
|
|||||||
));
|
));
|
||||||
pathogenRepository.save(new PathogenCatalogItem(
|
pathogenRepository.save(new PathogenCatalogItem(
|
||||||
null,
|
null,
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
blankToNull(mutation.code()),
|
blankToNull(mutation.code()),
|
||||||
mutation.name().trim(),
|
mutation.name().trim(),
|
||||||
@@ -316,6 +365,7 @@ public class CatalogService {
|
|||||||
if (existing.active() != mutation.active()) {
|
if (existing.active() != mutation.active()) {
|
||||||
pathogenRepository.save(new PathogenCatalogItem(
|
pathogenRepository.save(new PathogenCatalogItem(
|
||||||
existing.id(),
|
existing.id(),
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
existing.code(),
|
existing.code(),
|
||||||
existing.name(),
|
existing.name(),
|
||||||
@@ -327,11 +377,12 @@ public class CatalogService {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return listPathogenRows();
|
return listPathogenRowsForActor(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<AntibioticRow> saveAntibiotics(String actorId, List<AntibioticMutation> mutations) {
|
public List<AntibioticRow> saveAntibiotics(String actorId, List<AntibioticMutation> mutations) {
|
||||||
authorizationService.requireActiveUser(actorId, "Nicht berechtigt");
|
AppUser actor = requireActiveActor(actorId, "Nicht berechtigt");
|
||||||
|
String accountId = resolveAccountId(actor);
|
||||||
for (AntibioticMutation mutation : mutations) {
|
for (AntibioticMutation mutation : mutations) {
|
||||||
if (isBlank(mutation.name())) {
|
if (isBlank(mutation.name())) {
|
||||||
continue;
|
continue;
|
||||||
@@ -340,6 +391,7 @@ public class CatalogService {
|
|||||||
if (isBlank(mutation.id())) {
|
if (isBlank(mutation.id())) {
|
||||||
antibioticRepository.save(new AntibioticCatalogItem(
|
antibioticRepository.save(new AntibioticCatalogItem(
|
||||||
null,
|
null,
|
||||||
|
accountId,
|
||||||
UUID.randomUUID().toString(),
|
UUID.randomUUID().toString(),
|
||||||
blankToNull(mutation.code()),
|
blankToNull(mutation.code()),
|
||||||
mutation.name().trim(),
|
mutation.name().trim(),
|
||||||
@@ -353,11 +405,16 @@ public class CatalogService {
|
|||||||
String mutationId = requireText(mutation.id(), "Antibiotika-ID fehlt");
|
String mutationId = requireText(mutation.id(), "Antibiotika-ID fehlt");
|
||||||
AntibioticCatalogItem existing = antibioticRepository.findById(mutationId)
|
AntibioticCatalogItem existing = antibioticRepository.findById(mutationId)
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Antibiotikum nicht gefunden"));
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Antibiotikum nicht gefunden"));
|
||||||
|
// Sicherstellen, dass der Benutzer nur seine eigenen Daten bearbeiten kann
|
||||||
|
if (!accountId.equals(existing.accountId())) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.FORBIDDEN, "Nicht berechtigt");
|
||||||
|
}
|
||||||
boolean changed = !existing.name().equals(mutation.name().trim())
|
boolean changed = !existing.name().equals(mutation.name().trim())
|
||||||
|| !safeEquals(existing.code(), blankToNull(mutation.code()));
|
|| !safeEquals(existing.code(), blankToNull(mutation.code()));
|
||||||
if (changed) {
|
if (changed) {
|
||||||
antibioticRepository.save(new AntibioticCatalogItem(
|
antibioticRepository.save(new AntibioticCatalogItem(
|
||||||
existing.id(),
|
existing.id(),
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
existing.code(),
|
existing.code(),
|
||||||
existing.name(),
|
existing.name(),
|
||||||
@@ -368,6 +425,7 @@ public class CatalogService {
|
|||||||
));
|
));
|
||||||
antibioticRepository.save(new AntibioticCatalogItem(
|
antibioticRepository.save(new AntibioticCatalogItem(
|
||||||
null,
|
null,
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
blankToNull(mutation.code()),
|
blankToNull(mutation.code()),
|
||||||
mutation.name().trim(),
|
mutation.name().trim(),
|
||||||
@@ -381,6 +439,7 @@ public class CatalogService {
|
|||||||
if (existing.active() != mutation.active()) {
|
if (existing.active() != mutation.active()) {
|
||||||
antibioticRepository.save(new AntibioticCatalogItem(
|
antibioticRepository.save(new AntibioticCatalogItem(
|
||||||
existing.id(),
|
existing.id(),
|
||||||
|
existing.accountId(),
|
||||||
existing.businessKey(),
|
existing.businessKey(),
|
||||||
existing.code(),
|
existing.code(),
|
||||||
existing.name(),
|
existing.name(),
|
||||||
@@ -391,7 +450,7 @@ public class CatalogService {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return listAntibioticRows();
|
return listAntibioticRowsForActor(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<UserRow> listUsers(String actorId) {
|
public List<UserRow> listUsers(String actorId) {
|
||||||
@@ -653,28 +712,33 @@ public class CatalogService {
|
|||||||
backfillDefaultUserEmails();
|
backfillDefaultUserEmails();
|
||||||
removeLegacyPortalLoginField();
|
removeLegacyPortalLoginField();
|
||||||
migrateCustomerNumbers();
|
migrateCustomerNumbers();
|
||||||
|
migrateCatalogAccountIds();
|
||||||
ensureDefaultUser("Administrator", "admin@muh.local", "Admin123!", UserRole.ADMIN);
|
ensureDefaultUser("Administrator", "admin@muh.local", "Admin123!", UserRole.ADMIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Farmer requireActiveFarmer(String businessKey) {
|
public Farmer requireActiveFarmer(String actorId, String businessKey) {
|
||||||
return farmerRepository.findByActiveTrueOrderByNameAsc().stream()
|
AppUser actor = requireActiveActor(actorId, "Nicht berechtigt");
|
||||||
|
return listActiveFarmersForActor(actor).stream()
|
||||||
.filter(farmer -> farmer.businessKey().equals(businessKey))
|
.filter(farmer -> farmer.businessKey().equals(businessKey))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Landwirt nicht gefunden"));
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Landwirt nicht gefunden"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, PathogenCatalogItem> activePathogensByBusinessKey() {
|
public Map<String, PathogenCatalogItem> activePathogensByBusinessKey(String actorId) {
|
||||||
return pathogenRepository.findByActiveTrueOrderByNameAsc().stream()
|
AppUser actor = requireActiveActor(actorId, "Nicht berechtigt");
|
||||||
|
return listActivePathogensForActor(actor).stream()
|
||||||
.collect(Collectors.toMap(PathogenCatalogItem::businessKey, Function.identity()));
|
.collect(Collectors.toMap(PathogenCatalogItem::businessKey, Function.identity()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, AntibioticCatalogItem> activeAntibioticsByBusinessKey() {
|
public Map<String, AntibioticCatalogItem> activeAntibioticsByBusinessKey(String actorId) {
|
||||||
return antibioticRepository.findByActiveTrueOrderByNameAsc().stream()
|
AppUser actor = requireActiveActor(actorId, "Nicht berechtigt");
|
||||||
|
return listActiveAntibioticsForActor(actor).stream()
|
||||||
.collect(Collectors.toMap(AntibioticCatalogItem::businessKey, Function.identity()));
|
.collect(Collectors.toMap(AntibioticCatalogItem::businessKey, Function.identity()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, MedicationCatalogItem> activeMedicationsByBusinessKey() {
|
public Map<String, MedicationCatalogItem> activeMedicationsByBusinessKey(String actorId) {
|
||||||
return medicationRepository.findByActiveTrueOrderByNameAsc().stream()
|
AppUser actor = requireActiveActor(actorId, "Nicht berechtigt");
|
||||||
|
return listActiveMedicationsForActor(actor).stream()
|
||||||
.collect(Collectors.toMap(MedicationCatalogItem::businessKey, Function.identity()));
|
.collect(Collectors.toMap(MedicationCatalogItem::businessKey, Function.identity()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -999,6 +1063,82 @@ public class CatalogService {
|
|||||||
backfillDefaultUserEmail("admin", "admin@muh.local");
|
backfillDefaultUserEmail("admin", "admin@muh.local");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void migrateCatalogAccountIds() {
|
||||||
|
// Finde den ersten Admin-Benutzer als Fallback
|
||||||
|
String defaultAccountId = appUserRepository.findAll().stream()
|
||||||
|
.filter(user -> user.role() == UserRole.ADMIN)
|
||||||
|
.findFirst()
|
||||||
|
.map(AppUser::id)
|
||||||
|
.orElse(null);
|
||||||
|
|
||||||
|
if (defaultAccountId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
|
||||||
|
// Migriere Farmers ohne accountId
|
||||||
|
farmerRepository.findAll().stream()
|
||||||
|
.filter(farmer -> isBlank(farmer.accountId()))
|
||||||
|
.forEach(farmer -> farmerRepository.save(new Farmer(
|
||||||
|
farmer.id(),
|
||||||
|
defaultAccountId,
|
||||||
|
farmer.businessKey(),
|
||||||
|
farmer.name(),
|
||||||
|
farmer.email(),
|
||||||
|
farmer.active(),
|
||||||
|
farmer.supersedesId(),
|
||||||
|
farmer.createdAt(),
|
||||||
|
now
|
||||||
|
)));
|
||||||
|
|
||||||
|
// Migriere Medications ohne accountId
|
||||||
|
medicationRepository.findAll().stream()
|
||||||
|
.filter(med -> isBlank(med.accountId()))
|
||||||
|
.forEach(med -> medicationRepository.save(new MedicationCatalogItem(
|
||||||
|
med.id(),
|
||||||
|
defaultAccountId,
|
||||||
|
med.businessKey(),
|
||||||
|
med.name(),
|
||||||
|
med.category(),
|
||||||
|
med.active(),
|
||||||
|
med.supersedesId(),
|
||||||
|
med.createdAt(),
|
||||||
|
now
|
||||||
|
)));
|
||||||
|
|
||||||
|
// Migriere Pathogens ohne accountId
|
||||||
|
pathogenRepository.findAll().stream()
|
||||||
|
.filter(pathogen -> isBlank(pathogen.accountId()))
|
||||||
|
.forEach(pathogen -> pathogenRepository.save(new PathogenCatalogItem(
|
||||||
|
pathogen.id(),
|
||||||
|
defaultAccountId,
|
||||||
|
pathogen.businessKey(),
|
||||||
|
pathogen.code(),
|
||||||
|
pathogen.name(),
|
||||||
|
pathogen.kind(),
|
||||||
|
pathogen.active(),
|
||||||
|
pathogen.supersedesId(),
|
||||||
|
pathogen.createdAt(),
|
||||||
|
now
|
||||||
|
)));
|
||||||
|
|
||||||
|
// Migriere Antibiotics ohne accountId
|
||||||
|
antibioticRepository.findAll().stream()
|
||||||
|
.filter(antibiotic -> isBlank(antibiotic.accountId()))
|
||||||
|
.forEach(antibiotic -> antibioticRepository.save(new AntibioticCatalogItem(
|
||||||
|
antibiotic.id(),
|
||||||
|
defaultAccountId,
|
||||||
|
antibiotic.businessKey(),
|
||||||
|
antibiotic.code(),
|
||||||
|
antibiotic.name(),
|
||||||
|
antibiotic.active(),
|
||||||
|
antibiotic.supersedesId(),
|
||||||
|
antibiotic.createdAt(),
|
||||||
|
now
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
private void backfillDefaultUserEmail(String legacyPortalLogin, String email) {
|
private void backfillDefaultUserEmail(String legacyPortalLogin, String email) {
|
||||||
mongoTemplate.updateMulti(
|
mongoTemplate.updateMulti(
|
||||||
new Query(new Criteria().andOperator(
|
new Query(new Criteria().andOperator(
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package de.svencarstensen.muh.service;
|
||||||
|
|
||||||
|
import org.springframework.boot.ApplicationArguments;
|
||||||
|
import org.springframework.boot.ApplicationRunner;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class DefaultUserInitializer implements ApplicationRunner {
|
||||||
|
|
||||||
|
private final CatalogService catalogService;
|
||||||
|
|
||||||
|
public DefaultUserInitializer(CatalogService catalogService) {
|
||||||
|
this.catalogService = catalogService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run(ApplicationArguments args) {
|
||||||
|
catalogService.ensureDefaultUsers();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package de.svencarstensen.muh.service;
|
|
||||||
|
|
||||||
import de.svencarstensen.muh.domain.AntibioticCatalogItem;
|
|
||||||
import de.svencarstensen.muh.domain.Farmer;
|
|
||||||
import de.svencarstensen.muh.domain.MedicationCatalogItem;
|
|
||||||
import de.svencarstensen.muh.domain.MedicationCategory;
|
|
||||||
import de.svencarstensen.muh.domain.PathogenCatalogItem;
|
|
||||||
import de.svencarstensen.muh.domain.PathogenKind;
|
|
||||||
import de.svencarstensen.muh.repository.AntibioticCatalogRepository;
|
|
||||||
import de.svencarstensen.muh.repository.FarmerRepository;
|
|
||||||
import de.svencarstensen.muh.repository.MedicationCatalogRepository;
|
|
||||||
import de.svencarstensen.muh.repository.PathogenCatalogRepository;
|
|
||||||
import org.springframework.boot.ApplicationArguments;
|
|
||||||
import org.springframework.boot.ApplicationRunner;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class DemoDataInitializer implements ApplicationRunner {
|
|
||||||
|
|
||||||
private final FarmerRepository farmerRepository;
|
|
||||||
private final MedicationCatalogRepository medicationRepository;
|
|
||||||
private final PathogenCatalogRepository pathogenRepository;
|
|
||||||
private final AntibioticCatalogRepository antibioticRepository;
|
|
||||||
private final CatalogService catalogService;
|
|
||||||
|
|
||||||
public DemoDataInitializer(
|
|
||||||
FarmerRepository farmerRepository,
|
|
||||||
MedicationCatalogRepository medicationRepository,
|
|
||||||
PathogenCatalogRepository pathogenRepository,
|
|
||||||
AntibioticCatalogRepository antibioticRepository,
|
|
||||||
CatalogService catalogService
|
|
||||||
) {
|
|
||||||
this.farmerRepository = farmerRepository;
|
|
||||||
this.medicationRepository = medicationRepository;
|
|
||||||
this.pathogenRepository = pathogenRepository;
|
|
||||||
this.antibioticRepository = antibioticRepository;
|
|
||||||
this.catalogService = catalogService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(ApplicationArguments args) {
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
|
|
||||||
if (farmerRepository.count() == 0) {
|
|
||||||
farmerRepository.save(new Farmer(null, UUID.randomUUID().toString(), "Hof Hansen", "hansen@example.com", true, null, now, now));
|
|
||||||
farmerRepository.save(new Farmer(null, UUID.randomUUID().toString(), "Agrar Lindenblick", "lindenblick@example.com", true, null, now, now));
|
|
||||||
farmerRepository.save(new Farmer(null, UUID.randomUUID().toString(), "Gut Westerkamp", "westerkamp@example.com", true, null, now, now));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (medicationRepository.count() == 0) {
|
|
||||||
medicationRepository.save(new MedicationCatalogItem(null, UUID.randomUUID().toString(), "Mastijet", MedicationCategory.IN_UDDER, true, null, now, now));
|
|
||||||
medicationRepository.save(new MedicationCatalogItem(null, UUID.randomUUID().toString(), "Metacam", MedicationCategory.SYSTEMIC_PAIN, true, null, now, now));
|
|
||||||
medicationRepository.save(new MedicationCatalogItem(null, UUID.randomUUID().toString(), "Cobactan", MedicationCategory.SYSTEMIC_ANTIBIOTIC, true, null, now, now));
|
|
||||||
medicationRepository.save(new MedicationCatalogItem(null, UUID.randomUUID().toString(), "Orbeseal", MedicationCategory.DRY_SEALER, true, null, now, now));
|
|
||||||
medicationRepository.save(new MedicationCatalogItem(null, UUID.randomUUID().toString(), "Nafpenzal", MedicationCategory.DRY_ANTIBIOTIC, true, null, now, now));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pathogenRepository.count() == 0) {
|
|
||||||
pathogenRepository.save(new PathogenCatalogItem(null, UUID.randomUUID().toString(), "SAU", "Staph. aureus", PathogenKind.BACTERIAL, true, null, now, now));
|
|
||||||
pathogenRepository.save(new PathogenCatalogItem(null, UUID.randomUUID().toString(), "ECO", "E. coli", PathogenKind.BACTERIAL, true, null, now, now));
|
|
||||||
pathogenRepository.save(new PathogenCatalogItem(null, UUID.randomUUID().toString(), "NG", "Kein Wachstum", PathogenKind.NO_GROWTH, true, null, now, now));
|
|
||||||
pathogenRepository.save(new PathogenCatalogItem(null, UUID.randomUUID().toString(), "VER", "Verunreinigt", PathogenKind.CONTAMINATED, true, null, now, now));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (antibioticRepository.count() == 0) {
|
|
||||||
antibioticRepository.save(new AntibioticCatalogItem(null, UUID.randomUUID().toString(), "PEN", "Penicillin", true, null, now, now));
|
|
||||||
antibioticRepository.save(new AntibioticCatalogItem(null, UUID.randomUUID().toString(), "CEF", "Cefalexin", true, null, now, now));
|
|
||||||
antibioticRepository.save(new AntibioticCatalogItem(null, UUID.randomUUID().toString(), "ENR", "Enrofloxacin", true, null, now, now));
|
|
||||||
}
|
|
||||||
|
|
||||||
catalogService.ensureDefaultUsers();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -30,7 +30,7 @@ public class PortalService {
|
|||||||
Long sampleNumber,
|
Long sampleNumber,
|
||||||
LocalDate date
|
LocalDate date
|
||||||
) {
|
) {
|
||||||
List<CatalogService.FarmerOption> matchingFarmers = catalogService.activeCatalogSummary().farmers().stream()
|
List<CatalogService.FarmerOption> matchingFarmers = catalogService.activeCatalogSummary(actorId).farmers().stream()
|
||||||
.filter(farmer -> farmerQuery == null || farmerQuery.isBlank() || farmer.name().toLowerCase(Locale.ROOT).contains(farmerQuery.toLowerCase(Locale.ROOT)))
|
.filter(farmer -> farmerQuery == null || farmerQuery.isBlank() || farmer.name().toLowerCase(Locale.ROOT).contains(farmerQuery.toLowerCase(Locale.ROOT)))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ public class SampleService {
|
|||||||
public SampleDetail createSample(String actorId, RegistrationRequest request) {
|
public SampleDetail createSample(String actorId, RegistrationRequest request) {
|
||||||
AppUser actor = requireActor(actorId);
|
AppUser actor = requireActor(actorId);
|
||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
CatalogService.FarmerOption farmer = catalogService.activeCatalogSummary().farmers().stream()
|
CatalogService.FarmerOption farmer = catalogService.activeCatalogSummary(actorId).farmers().stream()
|
||||||
.filter(candidate -> candidate.businessKey().equals(request.farmerBusinessKey()))
|
.filter(candidate -> candidate.businessKey().equals(request.farmerBusinessKey()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Landwirt nicht gefunden"));
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Landwirt nicht gefunden"));
|
||||||
@@ -157,7 +157,7 @@ public class SampleService {
|
|||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Stammdaten können nicht mehr geändert werden");
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Stammdaten können nicht mehr geändert werden");
|
||||||
}
|
}
|
||||||
|
|
||||||
CatalogService.FarmerOption farmer = catalogService.activeCatalogSummary().farmers().stream()
|
CatalogService.FarmerOption farmer = catalogService.activeCatalogSummary(actorId).farmers().stream()
|
||||||
.filter(candidate -> candidate.businessKey().equals(request.farmerBusinessKey()))
|
.filter(candidate -> candidate.businessKey().equals(request.farmerBusinessKey()))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Landwirt nicht gefunden"));
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "Landwirt nicht gefunden"));
|
||||||
@@ -220,7 +220,7 @@ public class SampleService {
|
|||||||
current.put(quarter.quarterKey(), quarter);
|
current.put(quarter.quarterKey(), quarter);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, PathogenCatalogItem> pathogens = catalogService.activePathogensByBusinessKey();
|
Map<String, PathogenCatalogItem> pathogens = catalogService.activePathogensByBusinessKey(actorId);
|
||||||
List<QuarterFinding> updatedQuarters = new ArrayList<>();
|
List<QuarterFinding> updatedQuarters = new ArrayList<>();
|
||||||
for (AnamnesisQuarterRequest quarterRequest : request.quarters()) {
|
for (AnamnesisQuarterRequest quarterRequest : request.quarters()) {
|
||||||
QuarterFinding base = current.get(quarterRequest.quarterKey());
|
QuarterFinding base = current.get(quarterRequest.quarterKey());
|
||||||
@@ -284,7 +284,7 @@ public class SampleService {
|
|||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Antibiogramm kann nicht mehr geändert werden");
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Antibiogramm kann nicht mehr geändert werden");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, de.svencarstensen.muh.domain.AntibioticCatalogItem> antibiotics = catalogService.activeAntibioticsByBusinessKey();
|
Map<String, de.svencarstensen.muh.domain.AntibioticCatalogItem> antibiotics = catalogService.activeAntibioticsByBusinessKey(actorId);
|
||||||
Map<QuarterKey, QuarterAntibiogram> groups = new HashMap<>();
|
Map<QuarterKey, QuarterAntibiogram> groups = new HashMap<>();
|
||||||
Map<QuarterKey, QuarterFinding> quartersByKey = existing.quarters().stream()
|
Map<QuarterKey, QuarterFinding> quartersByKey = existing.quarters().stream()
|
||||||
.collect(java.util.stream.Collectors.toMap(QuarterFinding::quarterKey, quarter -> quarter));
|
.collect(java.util.stream.Collectors.toMap(QuarterFinding::quarterKey, quarter -> quarter));
|
||||||
@@ -435,7 +435,7 @@ public class SampleService {
|
|||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Therapie kann nicht bearbeitet werden");
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Therapie kann nicht bearbeitet werden");
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, de.svencarstensen.muh.domain.MedicationCatalogItem> medications = catalogService.activeMedicationsByBusinessKey();
|
Map<String, de.svencarstensen.muh.domain.MedicationCatalogItem> medications = catalogService.activeMedicationsByBusinessKey(actorId);
|
||||||
TherapyRecommendation therapy = new TherapyRecommendation(
|
TherapyRecommendation therapy = new TherapyRecommendation(
|
||||||
request.continueStarted(),
|
request.continueStarted(),
|
||||||
request.switchTherapy(),
|
request.switchTherapy(),
|
||||||
|
|||||||
@@ -26,30 +26,57 @@ public class CatalogController {
|
|||||||
|
|
||||||
@GetMapping("/catalogs/summary")
|
@GetMapping("/catalogs/summary")
|
||||||
public CatalogService.ActiveCatalogSummary catalogSummary() {
|
public CatalogService.ActiveCatalogSummary catalogSummary() {
|
||||||
return catalogService.activeCatalogSummary();
|
return catalogService.activeCatalogSummary(securitySupport.currentUser().id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Legacy admin endpoints - ADMIN only
|
||||||
@GetMapping("/admin")
|
@GetMapping("/admin")
|
||||||
public CatalogService.AdministrationOverview administrationOverview() {
|
public CatalogService.AdministrationOverview administrationOverview() {
|
||||||
return catalogService.administrationOverview(securitySupport.currentUser().id());
|
return catalogService.administrationOverview(securitySupport.currentUser().id());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/admin/farmers")
|
@PostMapping("/admin/farmers")
|
||||||
public List<CatalogService.FarmerRow> saveFarmers(@RequestBody List<CatalogService.FarmerMutation> mutations) {
|
public List<CatalogService.FarmerRow> saveFarmersAdmin(@RequestBody List<CatalogService.FarmerMutation> mutations) {
|
||||||
return catalogService.saveFarmers(securitySupport.currentUser().id(), mutations);
|
return catalogService.saveFarmers(securitySupport.currentUser().id(), mutations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/admin/medications")
|
@PostMapping("/admin/medications")
|
||||||
public List<CatalogService.MedicationRow> saveMedications(@RequestBody List<CatalogService.MedicationMutation> mutations) {
|
public List<CatalogService.MedicationRow> saveMedicationsAdmin(@RequestBody List<CatalogService.MedicationMutation> mutations) {
|
||||||
return catalogService.saveMedications(securitySupport.currentUser().id(), mutations);
|
return catalogService.saveMedications(securitySupport.currentUser().id(), mutations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/admin/pathogens")
|
@PostMapping("/admin/pathogens")
|
||||||
public List<CatalogService.PathogenRow> savePathogens(@RequestBody List<CatalogService.PathogenMutation> mutations) {
|
public List<CatalogService.PathogenRow> savePathogensAdmin(@RequestBody List<CatalogService.PathogenMutation> mutations) {
|
||||||
return catalogService.savePathogens(securitySupport.currentUser().id(), mutations);
|
return catalogService.savePathogens(securitySupport.currentUser().id(), mutations);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/admin/antibiotics")
|
@PostMapping("/admin/antibiotics")
|
||||||
|
public List<CatalogService.AntibioticRow> saveAntibioticsAdmin(@RequestBody List<CatalogService.AntibioticMutation> mutations) {
|
||||||
|
return catalogService.saveAntibiotics(securitySupport.currentUser().id(), mutations);
|
||||||
|
}
|
||||||
|
|
||||||
|
// New catalog endpoints - ADMIN and CUSTOMER
|
||||||
|
@GetMapping("/catalog/overview")
|
||||||
|
public CatalogService.AdministrationOverview catalogOverview() {
|
||||||
|
return catalogService.administrationOverview(securitySupport.currentUser().id());
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/catalog/farmers")
|
||||||
|
public List<CatalogService.FarmerRow> saveFarmers(@RequestBody List<CatalogService.FarmerMutation> mutations) {
|
||||||
|
return catalogService.saveFarmers(securitySupport.currentUser().id(), mutations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/catalog/medications")
|
||||||
|
public List<CatalogService.MedicationRow> saveMedications(@RequestBody List<CatalogService.MedicationMutation> mutations) {
|
||||||
|
return catalogService.saveMedications(securitySupport.currentUser().id(), mutations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/catalog/pathogens")
|
||||||
|
public List<CatalogService.PathogenRow> savePathogens(@RequestBody List<CatalogService.PathogenMutation> mutations) {
|
||||||
|
return catalogService.savePathogens(securitySupport.currentUser().id(), mutations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/catalog/antibiotics")
|
||||||
public List<CatalogService.AntibioticRow> saveAntibiotics(@RequestBody List<CatalogService.AntibioticMutation> mutations) {
|
public List<CatalogService.AntibioticRow> saveAntibiotics(@RequestBody List<CatalogService.AntibioticMutation> mutations) {
|
||||||
return catalogService.saveAntibiotics(securitySupport.currentUser().id(), mutations);
|
return catalogService.saveAntibiotics(securitySupport.currentUser().id(), mutations);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* - MINOR: New functionality (backward compatible)
|
* - MINOR: New functionality (backward compatible)
|
||||||
* - PATCH: Bug fixes (backward compatible)
|
* - PATCH: Bug fixes (backward compatible)
|
||||||
*/
|
*/
|
||||||
export const APP_VERSION = "0.8.0";
|
export const APP_VERSION = "0.9.2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build date - set at build time
|
* Build date - set at build time
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ export default function AdministrationPage() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function load() {
|
async function load() {
|
||||||
try {
|
try {
|
||||||
const response = await apiGet<AdministrationOverview>("/admin");
|
const response = await apiGet<AdministrationOverview>("/catalog/overview");
|
||||||
setDatasets(normalizeOverview(response));
|
setDatasets(normalizeOverview(response));
|
||||||
} catch (loadError) {
|
} catch (loadError) {
|
||||||
setMessage((loadError as Error).message);
|
setMessage((loadError as Error).message);
|
||||||
@@ -176,7 +176,7 @@ export default function AdministrationPage() {
|
|||||||
let response: EditableRow[];
|
let response: EditableRow[];
|
||||||
switch (selectedDataset) {
|
switch (selectedDataset) {
|
||||||
case "farmers":
|
case "farmers":
|
||||||
response = await apiPost<EditableRow[]>("/admin/farmers", rows.map((row) => ({
|
response = await apiPost<EditableRow[]>("/catalog/farmers", rows.map((row) => ({
|
||||||
id: row.id || null,
|
id: row.id || null,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
email: row.email || null,
|
email: row.email || null,
|
||||||
@@ -184,7 +184,7 @@ export default function AdministrationPage() {
|
|||||||
})));
|
})));
|
||||||
break;
|
break;
|
||||||
case "medications":
|
case "medications":
|
||||||
response = await apiPost<EditableRow[]>("/admin/medications", rows.map((row) => ({
|
response = await apiPost<EditableRow[]>("/catalog/medications", rows.map((row) => ({
|
||||||
id: row.id || null,
|
id: row.id || null,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
category: row.category,
|
category: row.category,
|
||||||
@@ -192,7 +192,7 @@ export default function AdministrationPage() {
|
|||||||
})));
|
})));
|
||||||
break;
|
break;
|
||||||
case "pathogens":
|
case "pathogens":
|
||||||
response = await apiPost<EditableRow[]>("/admin/pathogens", rows.map((row) => ({
|
response = await apiPost<EditableRow[]>("/catalog/pathogens", rows.map((row) => ({
|
||||||
id: row.id || null,
|
id: row.id || null,
|
||||||
code: row.code || null,
|
code: row.code || null,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
@@ -201,7 +201,7 @@ export default function AdministrationPage() {
|
|||||||
})));
|
})));
|
||||||
break;
|
break;
|
||||||
case "antibiotics":
|
case "antibiotics":
|
||||||
response = await apiPost<EditableRow[]>("/admin/antibiotics", rows.map((row) => ({
|
response = await apiPost<EditableRow[]>("/catalog/antibiotics", rows.map((row) => ({
|
||||||
id: row.id || null,
|
id: row.id || null,
|
||||||
code: row.code || null,
|
code: row.code || null,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
|
|||||||
Reference in New Issue
Block a user