implemented delete of energy community

This commit is contained in:
Bernhard Müller 2026-07-01 12:57:01 +02:00
parent 7d485f4079
commit caf05d3103
11 changed files with 83 additions and 25 deletions

1
.gitignore vendored
View file

@ -35,3 +35,4 @@ build/
/eeg_backend/eegportal.mv.db
/eegportal.mv.db
/eegportal.trace.db
/projekt_kontext.txt

31
ai-context.ps1 Normal file
View file

@ -0,0 +1,31 @@
$OutFile = "projekt_kontext.txt"
$Files = @()
# 1. Konfigurationen und Abhängigkeiten (Das Ökosystem)
if (Test-Path ".\pom.xml") { $Files += Get-Item ".\pom.xml" }
if (Test-Path ".\eeg_backend\pom.xml") { $Files += Get-Item ".\eeg_backend\pom.xml" }
if (Test-Path ".\eeg_frontend\package.json") { $Files += Get-Item ".\eeg_frontend\package.json" }
# 2. Backend: Java-Klassen (Spring Boot, Hibernate)
# Sucht nur im main-Verzeichnis, um Testklassen automatisch auszuschließen
if (Test-Path ".\eeg_backend\src\main\java") {
$Files += Get-ChildItem -Path ".\eeg_backend\src\main\java" -Filter *.java -Recurse
}
# 3. Frontend: Angular (TypeScript und HTML)
if (Test-Path ".\eeg_frontend\src\app") {
# Wir holen .ts und .html, filtern aber .spec.ts (Tests) hart heraus
$Files += Get-ChildItem -Path ".\eeg_frontend\src\app" -Include *.ts, *.html -Recurse | Where-Object { $_.Name -notmatch "\.spec\.ts$" }
}
# Ausgabe schreiben (UTF8 ist extrem wichtig!)
Clear-Content -Path $OutFile -ErrorAction SilentlyContinue
foreach ($f in $Files) {
"========================================" | Out-File -Append $OutFile -Encoding UTF8
"Datei: $($f.FullName)" | Out-File -Append $OutFile -Encoding UTF8
"========================================" | Out-File -Append $OutFile -Encoding UTF8
Get-Content $f.FullName -Encoding UTF8 | Out-File -Append $OutFile -Encoding UTF8
"`n" | Out-File -Append $OutFile -Encoding UTF8
}
Write-Host "Erfolgreich! Der Kontext für Backend und Frontend wurde in '$OutFile' gespeichert."

View file

@ -0,0 +1,5 @@
package at.mueller.eeg.backend.common.event;
import java.util.UUID;
public record UserRejectedEvent(UUID userId) {}

View file

@ -1,9 +1,6 @@
package at.mueller.eeg.backend.community.event.listener;
import at.mueller.eeg.backend.common.event.EdaTopologyCompletedEvent;
import at.mueller.eeg.backend.common.event.EdaTopologyFailedEvent;
import at.mueller.eeg.backend.common.event.InitiateMakoConsentEvent;
import at.mueller.eeg.backend.common.event.UserRegisteredEvent;
import at.mueller.eeg.backend.common.event.*;
import at.mueller.eeg.backend.common.exception.AtNumberAlreadyExistsException;
import at.mueller.eeg.backend.community.domain.MeteringPoint;
import at.mueller.eeg.backend.community.domain.PointType;
@ -77,4 +74,9 @@ public class MeteringPointEventListener {
meteringPointRepository.save(point);
});
}
@EventListener
public void handleUserRejected(UserRejectedEvent event) {
meteringPointRepository.deleteByUserId(event.userId());
}
}

View file

@ -11,4 +11,6 @@ public interface MeteringPointRepository extends JpaRepository<MeteringPoint, UU
List<MeteringPoint> findAllByUserId(UUID userId);
boolean existsByAtNumber(String atNumber);
void deleteByUserId(UUID userId);
}

View file

@ -66,6 +66,9 @@ public class EnergyCommunityService {
if (!energyCommunityRepository.existsById(id)) {
throw new IllegalArgumentException("Energy Community mit ID " + id + " existiert nicht.");
}
if (membershipRepository.existsByEnergyCommunityId(id)) {
throw new ResponseStatusException(HttpStatus.CONFLICT, "Die Energiegemeinschaft kann nicht gelöscht werden, da noch Zählpunkte zugeordnet sind.");
}
energyCommunityRepository.deleteById(id);
}

View file

@ -67,10 +67,7 @@ public class AdminIamController {
@Operation(summary = "User ablehnen",
description = "Lehnt den Antrag ab (z.B. weil Zählpunkt nicht ins Netz passt).")
public ResponseEntity<Void> rejectUser(@PathVariable UUID userId) {
// Logik: status auf REJECTED setzen oder User hard-löschen, je nach Datenschutz-Konzept
// Event feuern: UserRejectedEvent
adminIamService.rejectUser(userId);
return ResponseEntity.noContent().build();
return ResponseEntity.ok().build();
}
}

View file

@ -1,13 +1,16 @@
package at.mueller.eeg.backend.iam.service;
import at.mueller.eeg.backend.common.event.UserApprovedEvent;
import at.mueller.eeg.backend.common.event.UserRejectedEvent;
import at.mueller.eeg.backend.iam.domain.RegistrationStatus;
import at.mueller.eeg.backend.iam.domain.User;
import at.mueller.eeg.backend.iam.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;
import java.util.List;
import java.util.UUID;
@ -44,6 +47,16 @@ public class AdminIamService {
@Transactional
public void rejectUser(UUID userId) {
// Hier folgt später die Logik für das Ablehnen
User user = userRepository.findById(userId)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "User nicht gefunden"));
if (user.getStatus() != RegistrationStatus.PENDING) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Nur User im Status PENDING können abgelehnt werden.");
}
user.setStatus(RegistrationStatus.REJECTED);
userRepository.save(user);
eventPublisher.publishEvent(new UserRejectedEvent(user.getId()));
}
}

View file

@ -97,19 +97,22 @@ export class AdminEnergyCommunity implements OnInit {
}
canDelete(ec: EnergyCommunityDto): boolean {
// Wenn dein Backend z.B. die Anzahl der Mitglieder mitliefert:
// return !(ec as any).memberCount || (ec as any).memberCount === 0;
return true; // Vorerst true, bis die Relation im DTO steht
return !ec.memberCount || ec.memberCount === 0;
}
onDelete(id: string | undefined): void {
if (!id) return;
if (confirm('Möchtest du diese Energiegemeinschaft wirklich löschen?')) {
this.ecService.deleteEnergyCommunity(id).subscribe({
next: () => {
this.communities = this.communities.filter(c => c.id !== id);
},
error: (err) => console.error('Löschen fehlgeschlagen', err)
error: (err) => {
console.error('Löschen fehlgeschlagen', err);
const errorMsg = err.error?.message || 'Die Energiegemeinschaft konnte nicht gelöscht werden.';
alert(errorMsg);
}
});
}
}

View file

@ -61,7 +61,7 @@
Freigeben
</button>
<button (click)="rejectUser(user.id)"
<button (click)="rejectUser(user)"
class="inline-flex items-center justify-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-red-700 bg-white hover:bg-red-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 transition">
Ablehnen
</button>

View file

@ -58,21 +58,22 @@ export class AdminUserApprovalComponent implements OnInit {
});
}
public rejectUser(userId: string | undefined): void {
if (!userId) return;
this.errorMessage.set('');
public rejectUser(user: UserProfileResponse): void {
if (!user.id) {
console.error('Fehler: UserProfileResponse hat keine ID.');
return;
}
this.adminService.rejectUser(userId)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe({
if (confirm(`Möchtest du die Registrierung von ${user.firstName} ${user.lastName} wirklich ablehnen?`)) {
this.adminService.rejectUser(user.id).subscribe({
next: () => {
// Den abgelehnten User atomar aus der Liste filtern
this.pendingUsers.update(users => users.filter(user => user.id !== userId));
this.pendingUsers.update(users => users.filter(u => u.id !== user.id));
},
error: (error) => {
console.error(`Failed to reject user with ID ${userId}:`, error);
this.errorMessage.set('Der User konnte nicht abgelehnt werden.');
error: (err) => {
console.error('Fehler beim Ablehnen des Users', err);
alert(err.error?.message || 'Der User konnte nicht abgelehnt werden.');
}
});
}
}
}