Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refacto ack and read #8100

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.opfab.cards.publication.services.CardDeletionService;
import org.opfab.cards.publication.services.CardNotificationService;
import org.opfab.cards.publication.services.CardProcessingService;
import org.opfab.cards.publication.services.CardReadAndAckService;
import org.opfab.cards.publication.services.CardTranslationService;
import org.opfab.cards.publication.services.CardValidationService;
import org.opfab.cards.publication.services.ExternalAppService;
Expand All @@ -38,6 +39,8 @@ public class Services {

private final CardTranslationService cardTranslationService;

private final CardReadAndAckService cardReadAndAckService;

private final UserActionLogService userActionLogService;

private final CardValidationService cardValidationService;
Expand Down Expand Up @@ -65,7 +68,8 @@ public class Services {
this.cardTranslationService = new CardTranslationService(i18nRepository.get());
}
this.userActionLogService = userActionLogService;
CardNotificationService cardNotificationService = new CardNotificationService(eventBus, objectMapper, customScreenDataFields);
CardNotificationService cardNotificationService = new CardNotificationService(eventBus, objectMapper,
customScreenDataFields);
cardValidationService = new CardValidationService(cardRepository,
new ProcessRepositoryImpl(businessconfigUrl, eventBus));
cardDeletionService = new CardDeletionService(cardNotificationService, cardRepository, externalAppService,
Expand All @@ -76,6 +80,7 @@ public class Services {
checkPerimeterForCardSending,
authorizeToSendCardWithInvalidProcessState, cardSendingLimitCardCount, cardSendingLimitPeriod,
activateCardSendingLimiter);
cardReadAndAckService = new CardReadAndAckService(cardNotificationService, cardRepository);

}

Expand All @@ -91,6 +96,10 @@ public CardProcessingService getCardProcessingService() {
return cardProcessingService;
}

public CardReadAndAckService getCardReadAndAckService() {
return cardReadAndAckService;
}

public CardTranslationService getCardTranslationService() {
return cardTranslationService;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.opfab.cards.publication.repositories.UserBasedOperationResult;
import org.opfab.cards.publication.services.CardDeletionService;
import org.opfab.cards.publication.services.CardProcessingService;
import org.opfab.cards.publication.services.CardReadAndAckService;
import org.opfab.cards.publication.services.CardTranslationService;
import org.opfab.springtools.configuration.oauth.OpFabJwtAuthenticationToken;
import org.opfab.users.model.CurrentUserWithPerimeters;
Expand All @@ -44,6 +45,7 @@ public class CardController {
private CardDeletionService cardDeletionService;
private CardProcessingService cardProcessingService;
private CardTranslationService cardTranslationService;
private CardReadAndAckService cardReadAndAckService;
private UserActionLogService userActionLogService;

private @Value("${operatorfabric.userActionLogActivated:true}") boolean userActionLogActivated;
Expand All @@ -54,6 +56,7 @@ public class CardController {
cardTranslationService = services.getCardTranslationService();
userActionLogService = services.getUserActionLogService();
cardProcessingService = services.getCardProcessingService();
cardReadAndAckService = services.getCardReadAndAckService();

}

Expand Down Expand Up @@ -174,7 +177,7 @@ public Void postUserAcknowledgement(Principal principal,
OpFabJwtAuthenticationToken jwtPrincipal = (OpFabJwtAuthenticationToken) principal;
CurrentUserWithPerimeters user = (CurrentUserWithPerimeters) jwtPrincipal.getPrincipal();

UserBasedOperationResult result = cardProcessingService.processUserAcknowledgement(cardUid, user, entitiesAcks);
UserBasedOperationResult result = cardReadAndAckService.processUserAcknowledgement(cardUid, user, entitiesAcks);

if (!result.isCardFound())
response.setStatus(404);
Expand Down Expand Up @@ -202,7 +205,7 @@ public Void postUserCardRead(Principal principal,
OpFabJwtAuthenticationToken jwtPrincipal = (OpFabJwtAuthenticationToken) principal;
CurrentUserWithPerimeters user = (CurrentUserWithPerimeters) jwtPrincipal.getPrincipal();

UserBasedOperationResult result = cardProcessingService.processUserRead(cardUid, user.getUserData().getLogin());
UserBasedOperationResult result = cardReadAndAckService.processUserRead(cardUid, user.getUserData().getLogin());
if (!result.isCardFound())
response.setStatus(404);
else {
Expand All @@ -228,7 +231,7 @@ public Void deleteUserAcknowledgement(Principal principal, @PathVariable("cardUi
HttpServletResponse response) {
OpFabJwtAuthenticationToken jwtPrincipal = (OpFabJwtAuthenticationToken) principal;
CurrentUserWithPerimeters user = (CurrentUserWithPerimeters) jwtPrincipal.getPrincipal();
UserBasedOperationResult result = cardProcessingService.deleteUserAcknowledgement(cardUid, user, entitiesAcks);
UserBasedOperationResult result = cardReadAndAckService.deleteUserAcknowledgement(cardUid, user, entitiesAcks);
if (!result.isCardFound())
response.setStatus(404);
else {
Expand All @@ -253,7 +256,7 @@ public Void deleteUserRead(Principal principal, @PathVariable("cardUid") String
HttpServletResponse response) {
OpFabJwtAuthenticationToken jwtPrincipal = (OpFabJwtAuthenticationToken) principal;
CurrentUserWithPerimeters user = (CurrentUserWithPerimeters) jwtPrincipal.getPrincipal();
UserBasedOperationResult result = cardProcessingService.deleteUserRead(cardUid, user.getUserData().getLogin());
UserBasedOperationResult result = cardReadAndAckService.deleteUserRead(cardUid, user.getUserData().getLogin());
if (!result.isCardFound())
response.setStatus(404);
else {
Expand Down Expand Up @@ -303,7 +306,7 @@ public TranslatedField translateCardField(HttpServletRequest request, HttpServle
public Void postResetReadAndAcks(Principal principal,
@PathVariable("cardUid") String cardUid, HttpServletResponse response) {

UserBasedOperationResult result = cardProcessingService.resetReadAndAcks(cardUid);
UserBasedOperationResult result = cardReadAndAckService.resetReadAndAcks(cardUid);
if (!result.isCardFound())
response.setStatus(404);
else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import org.opfab.cards.publication.model.*;
import org.opfab.cards.publication.ratelimiter.CardSendingLimiter;
import org.opfab.cards.publication.repositories.CardRepository;
import org.opfab.cards.publication.repositories.UserBasedOperationResult;
import org.opfab.springtools.error.model.ApiError;
import org.opfab.springtools.error.model.ApiErrorException;
import org.opfab.users.model.CurrentUserWithPerimeters;
Expand Down Expand Up @@ -270,64 +269,6 @@ private String buildPublisherErrorMessage(Card card, String login) {
return errorMessagePrefix + ", the card cannot be sent";
}

public UserBasedOperationResult processUserAcknowledgement(String cardUid, CurrentUserWithPerimeters user,
List<String> entitiesAcks) {
if (cardPermissionControlService.isCurrentUserReadOnly(user) && entitiesAcks != null && !entitiesAcks.isEmpty())
throw new ApiErrorException(
new ApiError(HttpStatus.FORBIDDEN, "Acknowledgement impossible : User has READONLY opfab role"));

if (!user.getUserData().getEntities().containsAll(entitiesAcks))
throw new ApiErrorException(
new ApiError(HttpStatus.FORBIDDEN,
"Acknowledgement impossible : User is not member of all the entities given in the request"));

cardRepository.findByUid(cardUid).ifPresent(selectedCard -> cardNotificationService
.pushAckOfCardInEventBus(cardUid, selectedCard.id, entitiesAcks, CardOperationTypeEnum.ACK));

log.info("Set ack on card with uid {} for user {} and entities {}", cardUid, user.getUserData().getLogin(),
entitiesAcks);
return cardRepository.addUserAck(user.getUserData(), cardUid, entitiesAcks);
}

public UserBasedOperationResult processUserRead(String cardUid, String userName) {
log.info("Set read on card with uid {} for user {} ", cardUid, userName);
return cardRepository.addUserRead(userName, cardUid);
}

public UserBasedOperationResult deleteUserRead(String cardUid, String userName) {
log.info("Delete read on card with uid {} for user {} ", cardUid, userName);
return cardRepository.deleteUserRead(userName, cardUid);
}

public UserBasedOperationResult deleteUserAcknowledgement(String cardUid, CurrentUserWithPerimeters user,
List<String> entitiesAcks) {
log.info("Delete ack on card with uid {} for user {} and entities {} ", cardUid, user.getUserData().getLogin(),
entitiesAcks);

if (!user.getUserData().getEntities().containsAll(entitiesAcks))
throw new ApiErrorException(

new ApiError(HttpStatus.FORBIDDEN,
"Cancel acknowledgement impossible : User is not member of all the entities given in the request"));

cardRepository.findByUid(cardUid).ifPresent(selectedCard -> cardNotificationService
.pushAckOfCardInEventBus(cardUid, selectedCard.id, entitiesAcks, CardOperationTypeEnum.UNACK));

return cardRepository.deleteUserAck(user.getUserData().getLogin(), cardUid, entitiesAcks);

}

public UserBasedOperationResult resetReadAndAcks(String cardUid) {
log.info("Delete ack and reads on card with uid {} ", cardUid);
UserBasedOperationResult acksResult = cardRepository.deleteAcksAndReads(cardUid);
if (acksResult.isCardFound()) {
cardRepository.findByUid(cardUid)
.ifPresent(card -> cardNotificationService.notifyOneCard(card, CardOperationTypeEnum.UPDATE));
}

return acksResult;
}

public void resetRateLimiter() {
this.cardSendingLimiter.reset();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@

/* Copyright (c) 2018-2025, RTE (http://www.rte-france.com)
* See AUTHORS.txt
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
* This file is part of the OperatorFabric project.
*/

package org.opfab.cards.publication.services;

import org.opfab.cards.publication.model.*;
import org.opfab.cards.publication.repositories.CardRepository;
import org.opfab.cards.publication.repositories.UserBasedOperationResult;
import org.opfab.springtools.error.model.ApiError;
import org.opfab.springtools.error.model.ApiErrorException;
import org.opfab.users.model.CurrentUserWithPerimeters;
import org.springframework.http.HttpStatus;
import java.util.List;

public class CardReadAndAckService {

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CardReadAndAckService.class);

private CardNotificationService cardNotificationService;
private CardRepository cardRepository;
private CardPermissionControlService cardPermissionControlService;

public CardReadAndAckService(
CardNotificationService cardNotificationService,
CardRepository cardRepository) {
this.cardNotificationService = cardNotificationService;
this.cardRepository = cardRepository;
this.cardPermissionControlService = new CardPermissionControlService();

}

public UserBasedOperationResult processUserAcknowledgement(String cardUid, CurrentUserWithPerimeters user,
List<String> entitiesAcks) {
if (cardPermissionControlService.isCurrentUserReadOnly(user) && entitiesAcks != null && !entitiesAcks.isEmpty())
throw new ApiErrorException(
new ApiError(HttpStatus.FORBIDDEN, "Acknowledgement impossible : User has READONLY opfab role"));

if (!user.getUserData().getEntities().containsAll(entitiesAcks))
throw new ApiErrorException(
new ApiError(HttpStatus.FORBIDDEN,
"Acknowledgement impossible : User is not member of all the entities given in the request"));

cardRepository.findByUid(cardUid).ifPresent(selectedCard -> cardNotificationService
.pushAckOfCardInEventBus(cardUid, selectedCard.id, entitiesAcks, CardOperationTypeEnum.ACK));

log.info("Set ack on card with uid {} for user {} and entities {}", cardUid, user.getUserData().getLogin(),
entitiesAcks);
return cardRepository.addUserAck(user.getUserData(), cardUid, entitiesAcks);
}

public UserBasedOperationResult processUserRead(String cardUid, String userName) {
log.info("Set read on card with uid {} for user {} ", cardUid, userName);
return cardRepository.addUserRead(userName, cardUid);
}

public UserBasedOperationResult deleteUserRead(String cardUid, String userName) {
log.info("Delete read on card with uid {} for user {} ", cardUid, userName);
return cardRepository.deleteUserRead(userName, cardUid);
}

public UserBasedOperationResult deleteUserAcknowledgement(String cardUid, CurrentUserWithPerimeters user,
List<String> entitiesAcks) {
log.info("Delete ack on card with uid {} for user {} and entities {} ", cardUid, user.getUserData().getLogin(),
entitiesAcks);

if (!user.getUserData().getEntities().containsAll(entitiesAcks))
throw new ApiErrorException(

new ApiError(HttpStatus.FORBIDDEN,
"Cancel acknowledgement impossible : User is not member of all the entities given in the request"));

cardRepository.findByUid(cardUid).ifPresent(selectedCard -> cardNotificationService
.pushAckOfCardInEventBus(cardUid, selectedCard.id, entitiesAcks, CardOperationTypeEnum.UNACK));

return cardRepository.deleteUserAck(user.getUserData().getLogin(), cardUid, entitiesAcks);

}

public UserBasedOperationResult resetReadAndAcks(String cardUid) {
log.info("Delete ack and reads on card with uid {} ", cardUid);
UserBasedOperationResult acksResult = cardRepository.deleteAcksAndReads(cardUid);
if (acksResult.isCardFound()) {
cardRepository.findByUid(cardUid)
.ifPresent(card -> cardNotificationService.notifyOneCard(card, CardOperationTypeEnum.UPDATE));
}

return acksResult;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class CardProcessServiceShould {
private ExternalAppService externalAppService;

private CardProcessingService cardProcessingService;
private CardReadAndAckService cardReadAndAckService;
private CardTranslationService cardTranslationService;
private EventBusSpy eventBusSpy;
private CardNotificationService cardNotificationService;
Expand Down Expand Up @@ -110,6 +111,7 @@ public void init() {
cardRepositoryMock, externalAppService,
cardTranslationService, cardValidationService, true, true,
false, 1000, 3600, true);
cardReadAndAckService = new CardReadAndAckService(cardNotificationService, cardRepositoryMock);
user = TestHelpers.getCurrentUser();
currentUserWithPerimeters = TestHelpers.getCurrentUserWithPerimeter(user);
cardRepositoryMock.clear();
Expand Down Expand Up @@ -883,24 +885,16 @@ void GIVEN_a_user_with_the_write_right_in_perimeter_for_state1_WHEN_sending_card
Assertions.assertThat(TestHelpers.checkCardCount(cardRepositoryMock, 1)).isTrue();
}

@Test
void GIVEN_a_card_WHEN_reset_reads_and_acks_THEN_card_event_UPDATE_is_sent_to_eventBus() {
Card card = TestHelpers.generateOneCard();
cardProcessingService.processCard(card);
cardProcessingService.resetReadAndAcks(card.uid);
Assertions.assertThat(eventBusSpy.getMessagesSent().get(1)[1]).contains("{\"type\":\"UPDATE\"");
}

@Test
void GIVEN_an_existing_card_WHEN_update_card_CONTAINS_KEEP_EXISTING_ACKS_AND_READS_THEN_acks_and_reads_are_kept() {
Card card = TestHelpers.generateOneCard("entity2");
cardProcessingService.processUserCard(card, currentUserWithPerimeters, token);
cardProcessingService.processUserRead(card.uid,
cardReadAndAckService.processUserRead(card.uid,
currentUserWithPerimeters.getUserData().getLogin());
cardProcessingService.processUserRead(card.uid, "user2");
cardReadAndAckService.processUserRead(card.uid, "user2");

List<String> entitiesAcks = List.of("entity2");
cardProcessingService.processUserAcknowledgement(card.uid, currentUserWithPerimeters,
cardReadAndAckService.processUserAcknowledgement(card.uid, currentUserWithPerimeters,
entitiesAcks);
Assertions.assertThat(TestHelpers.checkCardCount(cardRepositoryMock, 1)).isTrue();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

/* Copyright (c) 2018-2025, RTE (http://www.rte-france.com)
* See AUTHORS.txt
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
* This file is part of the OperatorFabric project.
*/

package org.opfab.cards.publication.services;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.opfab.cards.publication.application.UnitTestApplication;
import org.opfab.cards.publication.mocks.CardRepositoryMock;
import org.opfab.cards.publication.model.Card;
import org.opfab.test.EventBusSpy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.fasterxml.jackson.databind.ObjectMapper;

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = { UnitTestApplication.class })
class CardReadAndAckServiceShould {

@Autowired
private ObjectMapper objectMapper;

private CardReadAndAckService cardReadAndAckService;
private EventBusSpy eventBusSpy;
private CardNotificationService cardNotificationService;

@Autowired
private CardRepositoryMock cardRepositoryMock;

@BeforeEach
void init() {
eventBusSpy = new EventBusSpy();
cardNotificationService = new CardNotificationService(eventBusSpy, objectMapper, null);
cardReadAndAckService = new CardReadAndAckService(
cardNotificationService,
cardRepositoryMock);
cardRepositoryMock.clear();
eventBusSpy.clearMessageSent();
}

@Test
void GIVEN_a_card_WHEN_reset_reads_and_acks_THEN_card_event_UPDATE_is_sent_to_eventBus() {
Card card = TestHelpers.generateOneCard();
cardRepositoryMock.saveCard(card);
cardReadAndAckService.resetReadAndAcks(card.uid);
Assertions.assertThat(eventBusSpy.getMessagesSent().get(0)[1]).contains("{\"type\":\"UPDATE\"");
}
}