From caf05d31035fb23e56d5a90d22d7721572c7726a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20M=C3=BCller?= Date: Wed, 1 Jul 2026 12:57:01 +0200 Subject: [PATCH] implemented delete of energy community --- .gitignore | 1 + ai-context.ps1 | 31 +++++++++++++++++++ .../common/event/UserRejectedEvent.java | 5 +++ .../listener/MeteringPointEventListener.java | 10 +++--- .../repository/MeteringPointRepository.java | 2 ++ .../service/EnergyCommunityService.java | 3 ++ .../backend/iam/api/AdminIamController.java | 5 +-- .../backend/iam/service/AdminIamService.java | 15 ++++++++- .../admin-energy-community.ts | 11 ++++--- .../admin-user-approval.html | 2 +- .../admin-user-approval.ts | 23 +++++++------- 11 files changed, 83 insertions(+), 25 deletions(-) create mode 100644 ai-context.ps1 create mode 100644 eeg_backend/src/main/java/at/mueller/eeg/backend/common/event/UserRejectedEvent.java diff --git a/.gitignore b/.gitignore index 85dabde..63fd2d6 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,4 @@ build/ /eeg_backend/eegportal.mv.db /eegportal.mv.db /eegportal.trace.db +/projekt_kontext.txt diff --git a/ai-context.ps1 b/ai-context.ps1 new file mode 100644 index 0000000..decb4dd --- /dev/null +++ b/ai-context.ps1 @@ -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." \ No newline at end of file diff --git a/eeg_backend/src/main/java/at/mueller/eeg/backend/common/event/UserRejectedEvent.java b/eeg_backend/src/main/java/at/mueller/eeg/backend/common/event/UserRejectedEvent.java new file mode 100644 index 0000000..eb35ec0 --- /dev/null +++ b/eeg_backend/src/main/java/at/mueller/eeg/backend/common/event/UserRejectedEvent.java @@ -0,0 +1,5 @@ +package at.mueller.eeg.backend.common.event; + +import java.util.UUID; + +public record UserRejectedEvent(UUID userId) {} \ No newline at end of file diff --git a/eeg_backend/src/main/java/at/mueller/eeg/backend/community/event/listener/MeteringPointEventListener.java b/eeg_backend/src/main/java/at/mueller/eeg/backend/community/event/listener/MeteringPointEventListener.java index 1244fa5..4312031 100644 --- a/eeg_backend/src/main/java/at/mueller/eeg/backend/community/event/listener/MeteringPointEventListener.java +++ b/eeg_backend/src/main/java/at/mueller/eeg/backend/community/event/listener/MeteringPointEventListener.java @@ -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()); + } } diff --git a/eeg_backend/src/main/java/at/mueller/eeg/backend/community/repository/MeteringPointRepository.java b/eeg_backend/src/main/java/at/mueller/eeg/backend/community/repository/MeteringPointRepository.java index c97c9e3..237d63f 100644 --- a/eeg_backend/src/main/java/at/mueller/eeg/backend/community/repository/MeteringPointRepository.java +++ b/eeg_backend/src/main/java/at/mueller/eeg/backend/community/repository/MeteringPointRepository.java @@ -11,4 +11,6 @@ public interface MeteringPointRepository extends JpaRepository findAllByUserId(UUID userId); boolean existsByAtNumber(String atNumber); + + void deleteByUserId(UUID userId); } diff --git a/eeg_backend/src/main/java/at/mueller/eeg/backend/community/service/EnergyCommunityService.java b/eeg_backend/src/main/java/at/mueller/eeg/backend/community/service/EnergyCommunityService.java index a96b39e..67e6bde 100644 --- a/eeg_backend/src/main/java/at/mueller/eeg/backend/community/service/EnergyCommunityService.java +++ b/eeg_backend/src/main/java/at/mueller/eeg/backend/community/service/EnergyCommunityService.java @@ -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); } diff --git a/eeg_backend/src/main/java/at/mueller/eeg/backend/iam/api/AdminIamController.java b/eeg_backend/src/main/java/at/mueller/eeg/backend/iam/api/AdminIamController.java index 4901d71..678f135 100644 --- a/eeg_backend/src/main/java/at/mueller/eeg/backend/iam/api/AdminIamController.java +++ b/eeg_backend/src/main/java/at/mueller/eeg/backend/iam/api/AdminIamController.java @@ -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 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(); } } \ No newline at end of file diff --git a/eeg_backend/src/main/java/at/mueller/eeg/backend/iam/service/AdminIamService.java b/eeg_backend/src/main/java/at/mueller/eeg/backend/iam/service/AdminIamService.java index ded21ef..b3306cb 100644 --- a/eeg_backend/src/main/java/at/mueller/eeg/backend/iam/service/AdminIamService.java +++ b/eeg_backend/src/main/java/at/mueller/eeg/backend/iam/service/AdminIamService.java @@ -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())); } } \ No newline at end of file diff --git a/eeg_frontend/src/app/pages/admin-energy-community/admin-energy-community.ts b/eeg_frontend/src/app/pages/admin-energy-community/admin-energy-community.ts index 5a88655..a8ed7f7 100644 --- a/eeg_frontend/src/app/pages/admin-energy-community/admin-energy-community.ts +++ b/eeg_frontend/src/app/pages/admin-energy-community/admin-energy-community.ts @@ -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); + } }); } } diff --git a/eeg_frontend/src/app/pages/admin-user-approval/admin-user-approval.html b/eeg_frontend/src/app/pages/admin-user-approval/admin-user-approval.html index 7cb453a..9c47788 100644 --- a/eeg_frontend/src/app/pages/admin-user-approval/admin-user-approval.html +++ b/eeg_frontend/src/app/pages/admin-user-approval/admin-user-approval.html @@ -61,7 +61,7 @@ Freigeben - diff --git a/eeg_frontend/src/app/pages/admin-user-approval/admin-user-approval.ts b/eeg_frontend/src/app/pages/admin-user-approval/admin-user-approval.ts index 2e1b08e..71fc0f2 100644 --- a/eeg_frontend/src/app/pages/admin-user-approval/admin-user-approval.ts +++ b/eeg_frontend/src/app/pages/admin-user-approval/admin-user-approval.ts @@ -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.'); } }); + } } }