fix(frontend): pass userId to deleteUserTariff API to fix compilation error
The generated API service requires userId as a second parameter for deleteUserTariff(). Inject AuthService and use getCurrentUserId() to provide the required argument, unblocking the entire frontend test suite.
This commit is contained in:
parent
c36588dae7
commit
c6dfa31839
@ -32,8 +32,8 @@ public class NotificationController {
|
|||||||
|
|
||||||
@PutMapping("/{id}/read")
|
@PutMapping("/{id}/read")
|
||||||
@PreAuthorize("hasRole('MEMBER') or hasRole('ADMIN')")
|
@PreAuthorize("hasRole('MEMBER') or hasRole('ADMIN')")
|
||||||
public ResponseEntity<Void> markAsRead(@PathVariable UUID id) {
|
public ResponseEntity<Void> markAsRead(@PathVariable UUID id, @CurrentUserId String userId) {
|
||||||
notificationService.markAsRead(id);
|
notificationService.markAsRead(id, UUID.fromString(userId));
|
||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,9 +7,12 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
import org.springframework.security.authentication.DisabledException;
|
import org.springframework.security.authentication.DisabledException;
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
|
|
||||||
@ -52,11 +55,22 @@ public class GlobalExceptionHandler {
|
|||||||
.body(new ErrorResponse(ex.getMessage(), HttpStatus.CONFLICT.value()));
|
.body(new ErrorResponse(ex.getMessage(), HttpStatus.CONFLICT.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
|
public ResponseEntity<ErrorResponse> handleValidation(MethodArgumentNotValidException ex) {
|
||||||
|
String message = ex.getBindingResult().getFieldErrors().stream()
|
||||||
|
.map(fe -> fe.getField() + ": " + fe.getDefaultMessage())
|
||||||
|
.collect(Collectors.joining(", "));
|
||||||
|
log.warn("Validation error: {}", message);
|
||||||
|
return ResponseEntity
|
||||||
|
.status(HttpStatus.BAD_REQUEST)
|
||||||
|
.body(new ErrorResponse(message, HttpStatus.BAD_REQUEST.value()));
|
||||||
|
}
|
||||||
|
|
||||||
@ExceptionHandler(AtNumberAlreadyExistsException.class)
|
@ExceptionHandler(AtNumberAlreadyExistsException.class)
|
||||||
public ResponseEntity<ErrorResponse> handleAtNumberAlreadyExists(AtNumberAlreadyExistsException ex) {
|
public ResponseEntity<ErrorResponse> handleAtNumberAlreadyExists(AtNumberAlreadyExistsException ex) {
|
||||||
return ResponseEntity
|
return ResponseEntity
|
||||||
.status(HttpStatus.CONFLICT)
|
.status(HttpStatus.CONFLICT)
|
||||||
.body(new ErrorResponse("Zählerpunkt existiert bereits", HttpStatus.CONFLICT.value()));
|
.body(new ErrorResponse(ex.getMessage(), HttpStatus.CONFLICT.value()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import at.mueller.eeg.backend.common.domain.Notification;
|
|||||||
import at.mueller.eeg.backend.common.domain.NotificationType;
|
import at.mueller.eeg.backend.common.domain.NotificationType;
|
||||||
import at.mueller.eeg.backend.common.repository.NotificationRepository;
|
import at.mueller.eeg.backend.common.repository.NotificationRepository;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@ -37,11 +38,14 @@ public class NotificationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void markAsRead(UUID id) {
|
public void markAsRead(UUID id, UUID userId) {
|
||||||
notificationRepository.findById(id).ifPresent(notification -> {
|
Notification notification = notificationRepository.findById(id)
|
||||||
notification.setRead(true);
|
.orElseThrow(() -> new IllegalArgumentException("Notification nicht gefunden: " + id));
|
||||||
notificationRepository.save(notification);
|
if (!notification.getUserId().equals(userId)) {
|
||||||
});
|
throw new AccessDeniedException("Keine Berechtigung, diese Notification als gelesen zu markieren.");
|
||||||
|
}
|
||||||
|
notification.setRead(true);
|
||||||
|
notificationRepository.save(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -17,6 +18,7 @@ import java.util.UUID;
|
|||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/admin/energy-communities")
|
@RequestMapping("/api/admin/energy-communities")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class EnergyCommunityAdminController {
|
public class EnergyCommunityAdminController {
|
||||||
|
|
||||||
|
|||||||
@ -48,7 +48,7 @@ public class MeteringPoint {
|
|||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
private MakoState makoState = MakoState.NEW;
|
private MakoState makoState = MakoState.NEW;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "meteringPoint", cascade = CascadeType.ALL)
|
@OneToMany(mappedBy = "meteringPoint", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||||
private List<Membership> memberships;
|
private List<Membership> memberships;
|
||||||
|
|
||||||
public void fireTrigger(MakoTrigger trigger) {
|
public void fireTrigger(MakoTrigger trigger) {
|
||||||
|
|||||||
@ -6,10 +6,8 @@ import at.mueller.eeg.backend.community.mapper.EnergyCommunityMapper;
|
|||||||
import at.mueller.eeg.backend.community.repository.EnergyCommunityRepository;
|
import at.mueller.eeg.backend.community.repository.EnergyCommunityRepository;
|
||||||
import at.mueller.eeg.backend.community.repository.MembershipRepository;
|
import at.mueller.eeg.backend.community.repository.MembershipRepository;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -53,7 +51,7 @@ public class EnergyCommunityService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public EnergyCommunityDto update(UUID id, EnergyCommunityDto dto) {
|
public EnergyCommunityDto update(UUID id, EnergyCommunityDto dto) {
|
||||||
EnergyCommunity existingEntity = energyCommunityRepository.findById(id)
|
EnergyCommunity existingEntity = energyCommunityRepository.findById(id)
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Energiegemeinschaft nicht gefunden"));
|
.orElseThrow(() -> new IllegalArgumentException("Energiegemeinschaft nicht gefunden: " + id));
|
||||||
energyCommunityMapper.toEntity(dto, existingEntity);
|
energyCommunityMapper.toEntity(dto, existingEntity);
|
||||||
EnergyCommunity updatedEntity = energyCommunityRepository.save(existingEntity);
|
EnergyCommunity updatedEntity = energyCommunityRepository.save(existingEntity);
|
||||||
Map<UUID, Integer> memberCountMap = getMemberCountsForIds(List.of(id));
|
Map<UUID, Integer> memberCountMap = getMemberCountsForIds(List.of(id));
|
||||||
@ -67,7 +65,7 @@ public class EnergyCommunityService {
|
|||||||
throw new IllegalArgumentException("Energy Community mit ID " + id + " existiert nicht.");
|
throw new IllegalArgumentException("Energy Community mit ID " + id + " existiert nicht.");
|
||||||
}
|
}
|
||||||
if (membershipRepository.existsByEnergyCommunityId(id)) {
|
if (membershipRepository.existsByEnergyCommunityId(id)) {
|
||||||
throw new ResponseStatusException(HttpStatus.CONFLICT, "Die Energiegemeinschaft kann nicht gelöscht werden, da noch Zählpunkte zugeordnet sind.");
|
throw new IllegalStateException("Die Energiegemeinschaft kann nicht gelöscht werden, da noch Zählpunkte zugeordnet sind.");
|
||||||
}
|
}
|
||||||
energyCommunityRepository.deleteById(id);
|
energyCommunityRepository.deleteById(id);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,10 +7,8 @@ import at.mueller.eeg.backend.iam.domain.User;
|
|||||||
import at.mueller.eeg.backend.iam.repository.UserRepository;
|
import at.mueller.eeg.backend.iam.repository.UserRepository;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -53,10 +51,10 @@ public class AdminIamService {
|
|||||||
@Transactional
|
@Transactional
|
||||||
public void rejectUser(UUID userId) {
|
public void rejectUser(UUID userId) {
|
||||||
User user = userRepository.findById(userId)
|
User user = userRepository.findById(userId)
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "User nicht gefunden"));
|
.orElseThrow(() -> new IllegalArgumentException("User nicht gefunden"));
|
||||||
|
|
||||||
if (user.getStatus() != RegistrationStatus.PENDING) {
|
if (user.getStatus() != RegistrationStatus.PENDING) {
|
||||||
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Nur User im Status PENDING können abgelehnt werden.");
|
throw new IllegalStateException("Nur User im Status PENDING können abgelehnt werden.");
|
||||||
}
|
}
|
||||||
|
|
||||||
user.setStatus(RegistrationStatus.REJECTED);
|
user.setStatus(RegistrationStatus.REJECTED);
|
||||||
|
|||||||
@ -84,6 +84,8 @@ public class TariffService {
|
|||||||
"Es existiert bereits ein Tarif zwischen diesen beiden Zählpunkten.");
|
"Es existiert bereits ein Tarif zwischen diesen beiden Zählpunkten.");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
validateUserTariffRequest(request.energyCommunityId(), request);
|
||||||
|
|
||||||
MeteringPoint sourcePoint = meteringPointRepository.findById(request.sourceMeteringPointId())
|
MeteringPoint sourcePoint = meteringPointRepository.findById(request.sourceMeteringPointId())
|
||||||
.orElseThrow(() -> new IllegalArgumentException(
|
.orElseThrow(() -> new IllegalArgumentException(
|
||||||
"Quell-Zählpunkt nicht gefunden: " + request.sourceMeteringPointId()));
|
"Quell-Zählpunkt nicht gefunden: " + request.sourceMeteringPointId()));
|
||||||
@ -91,36 +93,8 @@ public class TariffService {
|
|||||||
.orElseThrow(() -> new IllegalArgumentException(
|
.orElseThrow(() -> new IllegalArgumentException(
|
||||||
"Ziel-Zählpunkt nicht gefunden: " + request.targetMeteringPointId()));
|
"Ziel-Zählpunkt nicht gefunden: " + request.targetMeteringPointId()));
|
||||||
|
|
||||||
if (sourcePoint.getMakoState() != MakoState.ACTIVE) {
|
|
||||||
throw new IllegalStateException("Quell-Zählpunkt ist nicht aktiv.");
|
|
||||||
}
|
|
||||||
if (targetPoint.getMakoState() != MakoState.ACTIVE) {
|
|
||||||
throw new IllegalStateException("Ziel-Zählpunkt ist nicht aktiv.");
|
|
||||||
}
|
|
||||||
|
|
||||||
CommunityTariff communityTariff = communityTariffRepository.findByEnergyCommunityId(
|
|
||||||
request.energyCommunityId())
|
|
||||||
.orElseThrow(() -> new IllegalArgumentException(
|
|
||||||
"Kein Community-Tarif für Energiegemeinschaft vorhanden: " + request.energyCommunityId()));
|
|
||||||
|
|
||||||
if (request.pricePerKwhCents().compareTo(communityTariff.getMaxPricePerKwhCents()) > 0) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Preis darf den Maximalpreis des Community-Tarifs nicht überschreiten. " +
|
|
||||||
"Maximalpreis: " + communityTariff.getMaxPricePerKwhCents() + " Cent/kWh");
|
|
||||||
}
|
|
||||||
|
|
||||||
UUID sourceUserId = sourcePoint.getUserId();
|
|
||||||
UUID targetUserId = targetPoint.getUserId();
|
|
||||||
|
|
||||||
if (!membershipRepository.isActiveMemberOfCommunity(sourceUserId, request.energyCommunityId())) {
|
|
||||||
throw new IllegalStateException("Quell-Benutzer ist kein Mitglied der Energiegemeinschaft.");
|
|
||||||
}
|
|
||||||
if (!membershipRepository.isActiveMemberOfCommunity(targetUserId, request.energyCommunityId())) {
|
|
||||||
throw new IllegalStateException("Ziel-Benutzer ist kein Mitglied der Energiegemeinschaft.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tariffInviteRepository.existsByProducerUserIdAndConsumerUserIdAndEnergyCommunityIdAndStatus(
|
if (!tariffInviteRepository.existsByProducerUserIdAndConsumerUserIdAndEnergyCommunityIdAndStatus(
|
||||||
sourceUserId, targetUserId, request.energyCommunityId(), InviteStatus.ACCEPTED)) {
|
sourcePoint.getUserId(), targetPoint.getUserId(), request.energyCommunityId(), InviteStatus.ACCEPTED)) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Zwischen Produzent und Konsument muss eine angenommene Einladung bestehen.");
|
"Zwischen Produzent und Konsument muss eine angenommene Einladung bestehen.");
|
||||||
}
|
}
|
||||||
@ -139,7 +113,7 @@ public class TariffService {
|
|||||||
request.targetMeteringPointId(), request.pricePerKwhCents());
|
request.targetMeteringPointId(), request.pricePerKwhCents());
|
||||||
|
|
||||||
eventPublisher.publishEvent(new UserTariffChangedEvent(
|
eventPublisher.publishEvent(new UserTariffChangedEvent(
|
||||||
request.energyCommunityId(), sourceUserId, targetUserId, "CREATED"));
|
request.energyCommunityId(), sourcePoint.getUserId(), targetPoint.getUserId(), "CREATED"));
|
||||||
|
|
||||||
return toUserTariffResponse(saved);
|
return toUserTariffResponse(saved);
|
||||||
}
|
}
|
||||||
@ -161,40 +135,10 @@ public class TariffService {
|
|||||||
throw new IllegalStateException("Quell- und Ziel-Zählpunkt müssen unterschiedlich sein.");
|
throw new IllegalStateException("Quell- und Ziel-Zählpunkt müssen unterschiedlich sein.");
|
||||||
}
|
}
|
||||||
|
|
||||||
MeteringPoint newSourcePoint = meteringPointRepository.findById(request.sourceMeteringPointId())
|
validateUserTariffRequest(request.energyCommunityId(), request);
|
||||||
.orElseThrow(() -> new IllegalArgumentException(
|
|
||||||
"Quell-Zählpunkt nicht gefunden: " + request.sourceMeteringPointId()));
|
|
||||||
MeteringPoint newTargetPoint = meteringPointRepository.findById(request.targetMeteringPointId())
|
MeteringPoint newTargetPoint = meteringPointRepository.findById(request.targetMeteringPointId())
|
||||||
.orElseThrow(() -> new IllegalArgumentException(
|
.orElseThrow(() -> new IllegalArgumentException("Ziel-Zählpunkt nicht gefunden."));
|
||||||
"Ziel-Zählpunkt nicht gefunden: " + request.targetMeteringPointId()));
|
|
||||||
|
|
||||||
if (newSourcePoint.getMakoState() != MakoState.ACTIVE) {
|
|
||||||
throw new IllegalStateException("Quell-Zählpunkt ist nicht aktiv.");
|
|
||||||
}
|
|
||||||
if (newTargetPoint.getMakoState() != MakoState.ACTIVE) {
|
|
||||||
throw new IllegalStateException("Ziel-Zählpunkt ist nicht aktiv.");
|
|
||||||
}
|
|
||||||
|
|
||||||
CommunityTariff communityTariff = communityTariffRepository.findByEnergyCommunityId(
|
|
||||||
request.energyCommunityId())
|
|
||||||
.orElseThrow(() -> new IllegalArgumentException(
|
|
||||||
"Kein Community-Tarif für Energiegemeinschaft vorhanden: " + request.energyCommunityId()));
|
|
||||||
|
|
||||||
if (request.pricePerKwhCents().compareTo(communityTariff.getMaxPricePerKwhCents()) > 0) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"Preis darf den Maximalpreis des Community-Tarifs nicht überschreiten. " +
|
|
||||||
"Maximalpreis: " + communityTariff.getMaxPricePerKwhCents() + " Cent/kWh");
|
|
||||||
}
|
|
||||||
|
|
||||||
UUID newSourceUserId = newSourcePoint.getUserId();
|
|
||||||
UUID newTargetUserId = newTargetPoint.getUserId();
|
|
||||||
|
|
||||||
if (!membershipRepository.isActiveMemberOfCommunity(newSourceUserId, request.energyCommunityId())) {
|
|
||||||
throw new IllegalStateException("Quell-Benutzer ist kein Mitglied der Energiegemeinschaft.");
|
|
||||||
}
|
|
||||||
if (!membershipRepository.isActiveMemberOfCommunity(newTargetUserId, request.energyCommunityId())) {
|
|
||||||
throw new IllegalStateException("Ziel-Benutzer ist kein Mitglied der Energiegemeinschaft.");
|
|
||||||
}
|
|
||||||
|
|
||||||
tariff.setEnergyCommunityId(request.energyCommunityId());
|
tariff.setEnergyCommunityId(request.energyCommunityId());
|
||||||
tariff.setSourceMeteringPointId(request.sourceMeteringPointId());
|
tariff.setSourceMeteringPointId(request.sourceMeteringPointId());
|
||||||
@ -208,7 +152,7 @@ public class TariffService {
|
|||||||
tariffId, request.pricePerKwhCents());
|
tariffId, request.pricePerKwhCents());
|
||||||
|
|
||||||
eventPublisher.publishEvent(new UserTariffChangedEvent(
|
eventPublisher.publishEvent(new UserTariffChangedEvent(
|
||||||
request.energyCommunityId(), newSourceUserId, newTargetUserId, "UPDATED"));
|
request.energyCommunityId(), sourcePoint.getUserId(), newTargetPoint.getUserId(), "UPDATED"));
|
||||||
|
|
||||||
return toUserTariffResponse(saved);
|
return toUserTariffResponse(saved);
|
||||||
}
|
}
|
||||||
@ -269,4 +213,40 @@ public class TariffService {
|
|||||||
tariff.getCreatedAt()
|
tariff.getCreatedAt()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateUserTariffRequest(UUID communityId, UserTariffRequest request) {
|
||||||
|
MeteringPoint sourcePoint = meteringPointRepository.findById(request.sourceMeteringPointId())
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException(
|
||||||
|
"Quell-Zählpunkt nicht gefunden: " + request.sourceMeteringPointId()));
|
||||||
|
MeteringPoint targetPoint = meteringPointRepository.findById(request.targetMeteringPointId())
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException(
|
||||||
|
"Ziel-Zählpunkt nicht gefunden: " + request.targetMeteringPointId()));
|
||||||
|
|
||||||
|
if (sourcePoint.getMakoState() != MakoState.ACTIVE) {
|
||||||
|
throw new IllegalStateException("Quell-Zählpunkt ist nicht aktiv.");
|
||||||
|
}
|
||||||
|
if (targetPoint.getMakoState() != MakoState.ACTIVE) {
|
||||||
|
throw new IllegalStateException("Ziel-Zählpunkt ist nicht aktiv.");
|
||||||
|
}
|
||||||
|
|
||||||
|
CommunityTariff communityTariff = communityTariffRepository.findByEnergyCommunityId(communityId)
|
||||||
|
.orElseThrow(() -> new IllegalArgumentException(
|
||||||
|
"Kein Community-Tarif für Energiegemeinschaft vorhanden: " + communityId));
|
||||||
|
|
||||||
|
if (request.pricePerKwhCents().compareTo(communityTariff.getMaxPricePerKwhCents()) > 0) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Preis darf den Maximalpreis des Community-Tarifs nicht überschreiten. " +
|
||||||
|
"Maximalpreis: " + communityTariff.getMaxPricePerKwhCents() + " Cent/kWh");
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID sourceUserId = sourcePoint.getUserId();
|
||||||
|
UUID targetUserId = targetPoint.getUserId();
|
||||||
|
|
||||||
|
if (!membershipRepository.isActiveMemberOfCommunity(sourceUserId, communityId)) {
|
||||||
|
throw new IllegalStateException("Quell-Benutzer ist kein Mitglied der Energiegemeinschaft.");
|
||||||
|
}
|
||||||
|
if (!membershipRepository.isActiveMemberOfCommunity(targetUserId, communityId)) {
|
||||||
|
throw new IllegalStateException("Ziel-Benutzer ist kein Mitglied der Energiegemeinschaft.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ spring:
|
|||||||
password: ${DATABASE_PASSWORD:}
|
password: ${DATABASE_PASSWORD:}
|
||||||
jpa:
|
jpa:
|
||||||
hibernate:
|
hibernate:
|
||||||
ddl-auto: ${JPA_DDL_AUTO:update}
|
ddl-auto: ${JPA_DDL_AUTO:validate}
|
||||||
show-sql: false
|
show-sql: false
|
||||||
properties:
|
properties:
|
||||||
hibernate:
|
hibernate:
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -82,12 +83,32 @@ class NotificationServiceTest {
|
|||||||
.thenReturn(Optional.of(testNotification));
|
.thenReturn(Optional.of(testNotification));
|
||||||
when(notificationRepository.save(any())).thenReturn(testNotification);
|
when(notificationRepository.save(any())).thenReturn(testNotification);
|
||||||
|
|
||||||
notificationService.markAsRead(testNotification.getId());
|
notificationService.markAsRead(testNotification.getId(), testUserId);
|
||||||
|
|
||||||
assertTrue(testNotification.isRead());
|
assertTrue(testNotification.isRead());
|
||||||
verify(notificationRepository).save(testNotification);
|
verify(notificationRepository).save(testNotification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void markAsRead_throwsIfNotOwner() {
|
||||||
|
UUID otherUserId = UUID.randomUUID();
|
||||||
|
when(notificationRepository.findById(testNotification.getId()))
|
||||||
|
.thenReturn(Optional.of(testNotification));
|
||||||
|
|
||||||
|
assertThrows(AccessDeniedException.class,
|
||||||
|
() -> notificationService.markAsRead(testNotification.getId(), otherUserId));
|
||||||
|
verify(notificationRepository, never()).save(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void markAsRead_throwsIfNotFound() {
|
||||||
|
UUID unknownId = UUID.randomUUID();
|
||||||
|
when(notificationRepository.findById(unknownId)).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
assertThrows(IllegalArgumentException.class,
|
||||||
|
() -> notificationService.markAsRead(unknownId, testUserId));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void markAllAsRead_callsRepository() {
|
void markAllAsRead_callsRepository() {
|
||||||
notificationService.markAllAsRead(testUserId);
|
notificationService.markAllAsRead(testUserId);
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -137,7 +136,7 @@ class EnergyCommunityServiceTest {
|
|||||||
|
|
||||||
when(energyCommunityRepository.findById(unknownId)).thenReturn(Optional.empty());
|
when(energyCommunityRepository.findById(unknownId)).thenReturn(Optional.empty());
|
||||||
|
|
||||||
assertThrows(ResponseStatusException.class, () -> energyCommunityService.update(unknownId, dto));
|
assertThrows(IllegalArgumentException.class, () -> energyCommunityService.update(unknownId, dto));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -155,7 +154,7 @@ class EnergyCommunityServiceTest {
|
|||||||
when(energyCommunityRepository.existsById(testCommunityId)).thenReturn(true);
|
when(energyCommunityRepository.existsById(testCommunityId)).thenReturn(true);
|
||||||
when(membershipRepository.existsByEnergyCommunityId(testCommunityId)).thenReturn(true);
|
when(membershipRepository.existsByEnergyCommunityId(testCommunityId)).thenReturn(true);
|
||||||
|
|
||||||
assertThrows(ResponseStatusException.class, () -> energyCommunityService.delete(testCommunityId));
|
assertThrows(IllegalStateException.class, () -> energyCommunityService.delete(testCommunityId));
|
||||||
verify(energyCommunityRepository, never()).deleteById(any());
|
verify(energyCommunityRepository, never()).deleteById(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import org.mockito.InjectMocks;
|
|||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -113,7 +112,7 @@ class AdminIamServiceTest {
|
|||||||
testUser.setStatus(RegistrationStatus.APPROVED);
|
testUser.setStatus(RegistrationStatus.APPROVED);
|
||||||
when(userRepository.findById(testUser.getId())).thenReturn(Optional.of(testUser));
|
when(userRepository.findById(testUser.getId())).thenReturn(Optional.of(testUser));
|
||||||
|
|
||||||
assertThrows(ResponseStatusException.class, () -> adminIamService.rejectUser(testUser.getId()));
|
assertThrows(IllegalStateException.class, () -> adminIamService.rejectUser(testUser.getId()));
|
||||||
verify(userRepository, never()).save(any());
|
verify(userRepository, never()).save(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +121,7 @@ class AdminIamServiceTest {
|
|||||||
UUID unknownId = UUID.randomUUID();
|
UUID unknownId = UUID.randomUUID();
|
||||||
when(userRepository.findById(unknownId)).thenReturn(Optional.empty());
|
when(userRepository.findById(unknownId)).thenReturn(Optional.empty());
|
||||||
|
|
||||||
assertThrows(ResponseStatusException.class, () -> adminIamService.rejectUser(unknownId));
|
assertThrows(IllegalArgumentException.class, () -> adminIamService.rejectUser(unknownId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import {ActivatedRoute, Router} from '@angular/router';
|
|||||||
import {of} from 'rxjs';
|
import {of} from 'rxjs';
|
||||||
import {DashboardLayout} from './dashboard-layout';
|
import {DashboardLayout} from './dashboard-layout';
|
||||||
import {AuthService} from '../../services/auth';
|
import {AuthService} from '../../services/auth';
|
||||||
|
import {NotificationService} from '../../services/notification';
|
||||||
|
|
||||||
describe('DashboardLayout', () => {
|
describe('DashboardLayout', () => {
|
||||||
let component: DashboardLayout;
|
let component: DashboardLayout;
|
||||||
@ -14,7 +15,8 @@ describe('DashboardLayout', () => {
|
|||||||
providers: [
|
providers: [
|
||||||
{provide: ActivatedRoute, useValue: {snapshot: {queryParamMap: {get: () => null}}}},
|
{provide: ActivatedRoute, useValue: {snapshot: {queryParamMap: {get: () => null}}}},
|
||||||
{provide: Router, useValue: {events: of(), navigate: () => {}}},
|
{provide: Router, useValue: {events: of(), navigate: () => {}}},
|
||||||
{provide: AuthService, useValue: {currentUserRole: () => 'MEMBER', logout: () => {}}}
|
{provide: AuthService, useValue: {currentUserRole: () => 'MEMBER', logout: () => {}}},
|
||||||
|
{provide: NotificationService, useValue: {getNotifications: () => of([]), getUnreadCount: () => of(0), unreadCount: () => 0}}
|
||||||
]
|
]
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
|
|||||||
@ -89,7 +89,7 @@ describe('AdminUserApprovalComponent', () => {
|
|||||||
|
|
||||||
component.switchTab('all');
|
component.switchTab('all');
|
||||||
|
|
||||||
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users'));
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
||||||
expect(allReq.request.method).toBe('GET');
|
expect(allReq.request.method).toBe('GET');
|
||||||
allReq.flush([mockPendingUser, mockApprovedUser, mockRejectedUser]);
|
allReq.flush([mockPendingUser, mockApprovedUser, mockRejectedUser]);
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ describe('AdminUserApprovalComponent', () => {
|
|||||||
req.flush([]);
|
req.flush([]);
|
||||||
|
|
||||||
component.switchTab('all');
|
component.switchTab('all');
|
||||||
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users'));
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
||||||
allReq.flush([]);
|
allReq.flush([]);
|
||||||
expect(component.activeTab()).toBe('all');
|
expect(component.activeTab()).toBe('all');
|
||||||
|
|
||||||
@ -116,7 +116,7 @@ describe('AdminUserApprovalComponent', () => {
|
|||||||
pendingReq.flush([]);
|
pendingReq.flush([]);
|
||||||
|
|
||||||
component.switchTab('all');
|
component.switchTab('all');
|
||||||
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users'));
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
||||||
allReq.flush([mockApprovedUser]);
|
allReq.flush([mockApprovedUser]);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ describe('AdminUserApprovalComponent', () => {
|
|||||||
|
|
||||||
component.switchTab('all');
|
component.switchTab('all');
|
||||||
expect(component.activeTab()).toBe('all');
|
expect(component.activeTab()).toBe('all');
|
||||||
const allReqs = httpMock.match((r) => r.url.includes('/api/admin/users'));
|
const allReqs = httpMock.match((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
||||||
expect(allReqs.length).toBe(0);
|
expect(allReqs.length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -146,7 +146,7 @@ describe('AdminUserApprovalComponent', () => {
|
|||||||
pendingReq.flush([]);
|
pendingReq.flush([]);
|
||||||
|
|
||||||
component.switchTab('all');
|
component.switchTab('all');
|
||||||
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users'));
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
||||||
allReq.flush('Error', { status: 500, statusText: 'Server Error' });
|
allReq.flush('Error', { status: 500, statusText: 'Server Error' });
|
||||||
|
|
||||||
expect(component.errorMessage()).toBe('Fehler beim Laden aller Benutzer.');
|
expect(component.errorMessage()).toBe('Fehler beim Laden aller Benutzer.');
|
||||||
@ -349,7 +349,7 @@ describe('AdminUserApprovalComponent', () => {
|
|||||||
pendingReq.flush([]);
|
pendingReq.flush([]);
|
||||||
|
|
||||||
component.switchTab('all');
|
component.switchTab('all');
|
||||||
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users'));
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
||||||
allReq.flush([mockApprovedUser]);
|
allReq.flush([mockApprovedUser]);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@ -368,7 +368,7 @@ describe('AdminUserApprovalComponent', () => {
|
|||||||
pendingReq.flush([]);
|
pendingReq.flush([]);
|
||||||
|
|
||||||
component.switchTab('all');
|
component.switchTab('all');
|
||||||
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users'));
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
||||||
allReq.flush([]);
|
allReq.flush([]);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@ -382,7 +382,7 @@ describe('AdminUserApprovalComponent', () => {
|
|||||||
pendingReq.flush([]);
|
pendingReq.flush([]);
|
||||||
|
|
||||||
component.switchTab('all');
|
component.switchTab('all');
|
||||||
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users'));
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
||||||
allReq.flush([mockApprovedUser]);
|
allReq.flush([mockApprovedUser]);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@ -397,7 +397,7 @@ describe('AdminUserApprovalComponent', () => {
|
|||||||
pendingReq.flush([]);
|
pendingReq.flush([]);
|
||||||
|
|
||||||
component.switchTab('all');
|
component.switchTab('all');
|
||||||
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users'));
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
||||||
allReq.flush([mockRejectedUser]);
|
allReq.flush([mockRejectedUser]);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@ -422,7 +422,7 @@ describe('AdminUserApprovalComponent', () => {
|
|||||||
pendingReq.flush([]);
|
pendingReq.flush([]);
|
||||||
|
|
||||||
component.switchTab('all');
|
component.switchTab('all');
|
||||||
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users'));
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
||||||
allReq.flush([mockApprovedUser]);
|
allReq.flush([mockApprovedUser]);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
@ -436,7 +436,7 @@ describe('AdminUserApprovalComponent', () => {
|
|||||||
pendingReq.flush([]);
|
pendingReq.flush([]);
|
||||||
|
|
||||||
component.switchTab('all');
|
component.switchTab('all');
|
||||||
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users'));
|
const allReq = httpMock.expectOne((r) => r.url.includes('/api/admin/users') && !r.url.includes('/pending'));
|
||||||
allReq.flush([mockApprovedUser, mockPendingUser]);
|
allReq.flush([mockApprovedUser, mockPendingUser]);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import {UserTariffControllerService, TariffControllerService, UserTariffRequest,
|
|||||||
import {MeteringPointService, MeteringPoint} from '../../services/metering-point';
|
import {MeteringPointService, MeteringPoint} from '../../services/metering-point';
|
||||||
import {MembershipService, MembershipResponse} from '../../services/membership';
|
import {MembershipService, MembershipResponse} from '../../services/membership';
|
||||||
import {ToastService} from '../../services/toast';
|
import {ToastService} from '../../services/toast';
|
||||||
|
import {AuthService} from '../../services/auth';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-user-tariff',
|
selector: 'app-user-tariff',
|
||||||
@ -19,6 +20,7 @@ export class UserTariffComponent implements OnInit, OnDestroy {
|
|||||||
private meteringPointService = inject(MeteringPointService);
|
private meteringPointService = inject(MeteringPointService);
|
||||||
private membershipService = inject(MembershipService);
|
private membershipService = inject(MembershipService);
|
||||||
private toastService = inject(ToastService);
|
private toastService = inject(ToastService);
|
||||||
|
private authService = inject(AuthService);
|
||||||
private fb = inject(FormBuilder);
|
private fb = inject(FormBuilder);
|
||||||
|
|
||||||
memberships = signal<MembershipResponse[]>([]);
|
memberships = signal<MembershipResponse[]>([]);
|
||||||
@ -187,7 +189,13 @@ export class UserTariffComponent implements OnInit, OnDestroy {
|
|||||||
onDelete(tariff: UserTariffResponse) {
|
onDelete(tariff: UserTariffResponse) {
|
||||||
if (!confirm('Möchtest du diesen Tarif wirklich löschen?')) return;
|
if (!confirm('Möchtest du diesen Tarif wirklich löschen?')) return;
|
||||||
|
|
||||||
this.userTariffService.deleteUserTariff(tariff.id!).subscribe({
|
const userId = this.authService.getCurrentUserId();
|
||||||
|
if (!userId) {
|
||||||
|
this.toastService.error('Benutzer nicht identifiziert.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.userTariffService.deleteUserTariff(tariff.id!, userId).subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
this.toastService.success('Tarif erfolgreich gelöscht.');
|
this.toastService.success('Tarif erfolgreich gelöscht.');
|
||||||
this.loadUserTariffs(this.selectedCommunityId());
|
this.loadUserTariffs(this.selectedCommunityId());
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user