diff --git a/src/main/java/io/nickreuter/retroapi/notification/ActionType.java b/src/main/java/io/nickreuter/retroapi/notification/ActionType.java deleted file mode 100644 index 9cacde2..0000000 --- a/src/main/java/io/nickreuter/retroapi/notification/ActionType.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.nickreuter.retroapi.notification; - -public enum ActionType { - CREATE, - UPDATE, - DELETE -} diff --git a/src/main/java/io/nickreuter/retroapi/notification/EventType.java b/src/main/java/io/nickreuter/retroapi/notification/EventType.java new file mode 100644 index 0000000..9eceb51 --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/notification/EventType.java @@ -0,0 +1,14 @@ +package io.nickreuter.retroapi.notification; + +public enum EventType { + CREATE, + UPDATE, + DELETE, + TIMER_START, + TIMER_STOP, + FOCUS, + FOCUS_CLEAR, + SORT, + PHASE, + RETRO_FINISHED +} diff --git a/src/main/java/io/nickreuter/retroapi/notification/WebsocketConfig.java b/src/main/java/io/nickreuter/retroapi/notification/WebsocketConfig.java index b5054ed..adc2bce 100644 --- a/src/main/java/io/nickreuter/retroapi/notification/WebsocketConfig.java +++ b/src/main/java/io/nickreuter/retroapi/notification/WebsocketConfig.java @@ -89,9 +89,9 @@ public AuthorizationManager> messageAuthorizationManager(MessageMatch messages .simpTypeMatchers(UNSUBSCRIBE, DISCONNECT).permitAll() .nullDestMatcher().authenticated() - .simpSubscribeDestMatchers("/topic/*.thoughts").access(this::isAuthorizedRetroSubscription) - .simpSubscribeDestMatchers("/topic/*.finished").access(this::isAuthorizedRetroSubscription) - .simpSubscribeDestMatchers("/topic/*.action-items").access((this::isAuthorizedTeamSubscription)) + .simpSubscribeDestMatchers("/topic/retros.*.thoughts").access(this::isAuthorizedRetroSubscription) + .simpSubscribeDestMatchers("/topic/retros.*.events").access(this::isAuthorizedRetroSubscription) + .simpSubscribeDestMatchers("/topic/teams.*.action-items").access(this::isAuthorizedTeamSubscription) .simpTypeMatchers(MESSAGE, SUBSCRIBE).denyAll() .anyMessage().denyAll(); return messages.build(); @@ -158,7 +158,7 @@ ChannelInterceptor csrfChannelInterceptor() { } private AuthorizationDecision isAuthorizedRetroSubscription(Supplier authentication, MessageAuthorizationContext object) { - var ids = getIdFromTopic(object, "^/topic/(?.*)\\..*"); + var ids = getIdFromTopic(object, "^/topic/retros\\.(?[^.]+)\\..*"); if (!ids.find()) { return new AuthorizationDecision(false); } @@ -181,7 +181,7 @@ private AuthorizationDecision isAuthorizedRetroSubscription(Supplier authentication, MessageAuthorizationContext object) { - var ids = getIdFromTopic(object, "^/topic/(?.*)\\..*$"); + var ids = getIdFromTopic(object, "^/topic/teams\\.(?[^.]+)\\..*$"); AuthorizationDecision isAuthorized = ids.find() // TODO: Add error handling for when this fails because the UUID is too big ? new AuthorizationDecision(userMappingAuthorizationService.isUserMemberOfTeam(authentication.get(), UUID.fromString(ids.group("teamId")))) diff --git a/src/main/java/io/nickreuter/retroapi/notification/event/ActionItemEvent.java b/src/main/java/io/nickreuter/retroapi/notification/event/ActionItemEvent.java index 5bc333d..f2d3c03 100644 --- a/src/main/java/io/nickreuter/retroapi/notification/event/ActionItemEvent.java +++ b/src/main/java/io/nickreuter/retroapi/notification/event/ActionItemEvent.java @@ -1,16 +1,16 @@ package io.nickreuter.retroapi.notification.event; -import io.nickreuter.retroapi.notification.ActionType; +import io.nickreuter.retroapi.notification.EventType; import io.nickreuter.retroapi.team.actionitem.ActionItemEntity; import java.util.UUID; public class ActionItemEvent extends BaseEvent{ - private static final String ROUTE_STRING = "/topic/%s.action-items"; + private static final String ROUTE_STRING = "/topic/teams.%s.action-items"; private final UUID teamId; - public ActionItemEvent(Object source, ActionType actionType, ActionItemEntity payload, UUID teamId) { - super(source, actionType, payload); + public ActionItemEvent(Object source, EventType eventType, ActionItemEntity payload, UUID teamId) { + super(source, eventType, payload); this.teamId = teamId; } diff --git a/src/main/java/io/nickreuter/retroapi/notification/event/BaseEvent.java b/src/main/java/io/nickreuter/retroapi/notification/event/BaseEvent.java index e36bdb3..8bc1a7b 100644 --- a/src/main/java/io/nickreuter/retroapi/notification/event/BaseEvent.java +++ b/src/main/java/io/nickreuter/retroapi/notification/event/BaseEvent.java @@ -1,17 +1,17 @@ package io.nickreuter.retroapi.notification.event; -import io.nickreuter.retroapi.notification.ActionType; +import io.nickreuter.retroapi.notification.EventType; import lombok.Getter; import org.springframework.context.ApplicationEvent; @Getter public abstract class BaseEvent extends ApplicationEvent { - private final ActionType actionType; + private final EventType eventType; private final Object payload; - public BaseEvent(Object source, ActionType actionType, Object payload) { + public BaseEvent(Object source, EventType eventType, Object payload) { super(source); - this.actionType = actionType; + this.eventType = eventType; this.payload = payload; } diff --git a/src/main/java/io/nickreuter/retroapi/notification/event/RetroFinishedEvent.java b/src/main/java/io/nickreuter/retroapi/notification/event/RetroFinishedEvent.java index 2b05e88..25dff14 100644 --- a/src/main/java/io/nickreuter/retroapi/notification/event/RetroFinishedEvent.java +++ b/src/main/java/io/nickreuter/retroapi/notification/event/RetroFinishedEvent.java @@ -1,15 +1,15 @@ package io.nickreuter.retroapi.notification.event; -import io.nickreuter.retroapi.notification.ActionType; +import io.nickreuter.retroapi.notification.EventType; import java.util.UUID; public class RetroFinishedEvent extends BaseEvent { - private static final String ROUTE_STRING = "/topic/%s.finished"; + private static final String ROUTE_STRING = "/topic/retros.%s.events"; private final UUID retroId; - public RetroFinishedEvent(Object source, ActionType actionType, boolean isFinished, UUID retroId) { - super(source, actionType, isFinished); + public RetroFinishedEvent(Object source, boolean isFinished, UUID retroId) { + super(source, EventType.RETRO_FINISHED, isFinished); this.retroId = retroId; } diff --git a/src/main/java/io/nickreuter/retroapi/notification/event/ThoughtEvent.java b/src/main/java/io/nickreuter/retroapi/notification/event/ThoughtEvent.java index ccf3c73..3e67f86 100644 --- a/src/main/java/io/nickreuter/retroapi/notification/event/ThoughtEvent.java +++ b/src/main/java/io/nickreuter/retroapi/notification/event/ThoughtEvent.java @@ -1,16 +1,16 @@ package io.nickreuter.retroapi.notification.event; -import io.nickreuter.retroapi.notification.ActionType; +import io.nickreuter.retroapi.notification.EventType; import io.nickreuter.retroapi.retro.thought.ThoughtEntity; import java.util.UUID; public class ThoughtEvent extends BaseEvent { - private static final String ROUTE_STRING = "/topic/%s.thoughts"; + private static final String ROUTE_STRING = "/topic/retros.%s.thoughts"; private final UUID retroId; - public ThoughtEvent(Object source, ActionType actionType, ThoughtEntity payload, UUID retroId) { - super(source, actionType, payload); + public ThoughtEvent(Object source, EventType eventType, ThoughtEntity payload, UUID retroId) { + super(source, eventType, payload); this.retroId = retroId; } diff --git a/src/main/java/io/nickreuter/retroapi/retro/RetroService.java b/src/main/java/io/nickreuter/retroapi/retro/RetroService.java index c7e7d8a..8597350 100644 --- a/src/main/java/io/nickreuter/retroapi/retro/RetroService.java +++ b/src/main/java/io/nickreuter/retroapi/retro/RetroService.java @@ -1,6 +1,5 @@ package io.nickreuter.retroapi.retro; -import io.nickreuter.retroapi.notification.ActionType; import io.nickreuter.retroapi.notification.event.RetroFinishedEvent; import io.nickreuter.retroapi.retro.template.Template; import org.springframework.context.ApplicationEventPublisher; @@ -53,6 +52,6 @@ public void setFinished(UUID retroId, boolean finished) throws RetroNotFoundExce var retro = retroRepository.findById(retroId).orElseThrow(RetroNotFoundException::new); retro.setFinished(finished); retroRepository.save(retro); - applicationEventPublisher.publishEvent(new RetroFinishedEvent(this, ActionType.UPDATE, finished, retroId)); + applicationEventPublisher.publishEvent(new RetroFinishedEvent(this, finished, retroId)); } } diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/FocusRequest.java b/src/main/java/io/nickreuter/retroapi/retro/event/FocusRequest.java new file mode 100644 index 0000000..ba8cff1 --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/FocusRequest.java @@ -0,0 +1,5 @@ +package io.nickreuter.retroapi.retro.event; + +import java.util.UUID; + +public record FocusRequest(UUID thoughtId) {} diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/PhaseRequest.java b/src/main/java/io/nickreuter/retroapi/retro/event/PhaseRequest.java new file mode 100644 index 0000000..9285c34 --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/PhaseRequest.java @@ -0,0 +1,3 @@ +package io.nickreuter.retroapi.retro.event; + +public record PhaseRequest(String phase) {} diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/RetroEventController.java b/src/main/java/io/nickreuter/retroapi/retro/event/RetroEventController.java new file mode 100644 index 0000000..84f7fa8 --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/RetroEventController.java @@ -0,0 +1,59 @@ +package io.nickreuter.retroapi.retro.event; + +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.UUID; + +@RestController +@RequestMapping("/api/teams/{teamId}/retros/{retroId}/events") +public class RetroEventController { + private final RetroEventService retroEventService; + + public RetroEventController(RetroEventService retroEventService) { + this.retroEventService = retroEventService; + } + + @PostMapping("/timer-start") + @PreAuthorize("@userMappingAuthorizationService.isUserMemberOfTeam(authentication, #teamId)") + public ResponseEntity startTimer(@PathVariable UUID teamId, @PathVariable UUID retroId, @RequestBody TimerStartRequest request) { + retroEventService.publishTimerStart(retroId, request.durationSeconds()); + return ResponseEntity.ok().build(); + } + + @PostMapping("/timer-stop") + @PreAuthorize("@userMappingAuthorizationService.isUserMemberOfTeam(authentication, #teamId)") + public ResponseEntity stopTimer(@PathVariable UUID teamId, @PathVariable UUID retroId) { + retroEventService.publishTimerStop(retroId); + return ResponseEntity.ok().build(); + } + + @PostMapping("/focus") + @PreAuthorize("@userMappingAuthorizationService.isUserMemberOfTeam(authentication, #teamId)") + public ResponseEntity focusThought(@PathVariable UUID teamId, @PathVariable UUID retroId, @RequestBody FocusRequest request) { + retroEventService.publishFocus(retroId, request.thoughtId()); + return ResponseEntity.ok().build(); + } + + @PostMapping("/focus-clear") + @PreAuthorize("@userMappingAuthorizationService.isUserMemberOfTeam(authentication, #teamId)") + public ResponseEntity clearFocus(@PathVariable UUID teamId, @PathVariable UUID retroId) { + retroEventService.publishFocusClear(retroId); + return ResponseEntity.ok().build(); + } + + @PostMapping("/sort") + @PreAuthorize("@userMappingAuthorizationService.isUserMemberOfTeam(authentication, #teamId)") + public ResponseEntity sortColumn(@PathVariable UUID teamId, @PathVariable UUID retroId, @RequestBody SortRequest request) { + retroEventService.publishSort(retroId, request.column(), request.direction()); + return ResponseEntity.ok().build(); + } + + @PostMapping("/phase") + @PreAuthorize("@userMappingAuthorizationService.isUserMemberOfTeam(authentication, #teamId)") + public ResponseEntity changePhase(@PathVariable UUID teamId, @PathVariable UUID retroId, @RequestBody PhaseRequest request) { + retroEventService.publishPhase(retroId, request.phase()); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/RetroEventService.java b/src/main/java/io/nickreuter/retroapi/retro/event/RetroEventService.java new file mode 100644 index 0000000..8fd9ea6 --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/RetroEventService.java @@ -0,0 +1,45 @@ +package io.nickreuter.retroapi.retro.event; + +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.stereotype.Service; + +import java.time.Instant; +import java.util.Map; +import java.util.UUID; + +@Service +public class RetroEventService { + private final ApplicationEventPublisher applicationEventPublisher; + + public RetroEventService(ApplicationEventPublisher applicationEventPublisher) { + this.applicationEventPublisher = applicationEventPublisher; + } + + public void publishTimerStart(UUID retroId, int durationSeconds) { + var payload = Map.of("durationSeconds", durationSeconds, "startedAt", Instant.now().toString()); + applicationEventPublisher.publishEvent(new RetroTimerStartEvent(this, payload, retroId)); + } + + public void publishTimerStop(UUID retroId) { + applicationEventPublisher.publishEvent(new RetroTimerStopEvent(this, null, retroId)); + } + + public void publishFocus(UUID retroId, UUID thoughtId) { + var payload = Map.of("thoughtId", thoughtId.toString()); + applicationEventPublisher.publishEvent(new RetroFocusEvent(this, payload, retroId)); + } + + public void publishFocusClear(UUID retroId) { + applicationEventPublisher.publishEvent(new RetroFocusClearEvent(this, null, retroId)); + } + + public void publishSort(UUID retroId, String column, String direction) { + var payload = Map.of("column", column, "direction", direction); + applicationEventPublisher.publishEvent(new RetroSortEvent(this, payload, retroId)); + } + + public void publishPhase(UUID retroId, String phase) { + var payload = Map.of("phase", phase); + applicationEventPublisher.publishEvent(new RetroPhaseEvent(this, payload, retroId)); + } +} diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/RetroFocusClearEvent.java b/src/main/java/io/nickreuter/retroapi/retro/event/RetroFocusClearEvent.java new file mode 100644 index 0000000..c572aba --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/RetroFocusClearEvent.java @@ -0,0 +1,21 @@ +package io.nickreuter.retroapi.retro.event; + +import io.nickreuter.retroapi.notification.EventType; +import io.nickreuter.retroapi.notification.event.BaseEvent; + +import java.util.UUID; + +public class RetroFocusClearEvent extends BaseEvent { + private static final String ROUTE_STRING = "/topic/retros.%s.events"; + private final UUID retroId; + + public RetroFocusClearEvent(Object source, Object payload, UUID retroId) { + super(source, EventType.FOCUS_CLEAR, payload); + this.retroId = retroId; + } + + @Override + public String getRoute() { + return String.format(ROUTE_STRING, retroId); + } +} diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/RetroFocusEvent.java b/src/main/java/io/nickreuter/retroapi/retro/event/RetroFocusEvent.java new file mode 100644 index 0000000..938c877 --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/RetroFocusEvent.java @@ -0,0 +1,21 @@ +package io.nickreuter.retroapi.retro.event; + +import io.nickreuter.retroapi.notification.EventType; +import io.nickreuter.retroapi.notification.event.BaseEvent; + +import java.util.UUID; + +public class RetroFocusEvent extends BaseEvent { + private static final String ROUTE_STRING = "/topic/retros.%s.events"; + private final UUID retroId; + + public RetroFocusEvent(Object source, Object payload, UUID retroId) { + super(source, EventType.FOCUS, payload); + this.retroId = retroId; + } + + @Override + public String getRoute() { + return String.format(ROUTE_STRING, retroId); + } +} diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/RetroPhaseEvent.java b/src/main/java/io/nickreuter/retroapi/retro/event/RetroPhaseEvent.java new file mode 100644 index 0000000..c3301a1 --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/RetroPhaseEvent.java @@ -0,0 +1,21 @@ +package io.nickreuter.retroapi.retro.event; + +import io.nickreuter.retroapi.notification.EventType; +import io.nickreuter.retroapi.notification.event.BaseEvent; + +import java.util.UUID; + +public class RetroPhaseEvent extends BaseEvent { + private static final String ROUTE_STRING = "/topic/retros.%s.events"; + private final UUID retroId; + + public RetroPhaseEvent(Object source, Object payload, UUID retroId) { + super(source, EventType.PHASE, payload); + this.retroId = retroId; + } + + @Override + public String getRoute() { + return String.format(ROUTE_STRING, retroId); + } +} diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/RetroSortEvent.java b/src/main/java/io/nickreuter/retroapi/retro/event/RetroSortEvent.java new file mode 100644 index 0000000..1ab87e1 --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/RetroSortEvent.java @@ -0,0 +1,21 @@ +package io.nickreuter.retroapi.retro.event; + +import io.nickreuter.retroapi.notification.EventType; +import io.nickreuter.retroapi.notification.event.BaseEvent; + +import java.util.UUID; + +public class RetroSortEvent extends BaseEvent { + private static final String ROUTE_STRING = "/topic/retros.%s.events"; + private final UUID retroId; + + public RetroSortEvent(Object source, Object payload, UUID retroId) { + super(source, EventType.SORT, payload); + this.retroId = retroId; + } + + @Override + public String getRoute() { + return String.format(ROUTE_STRING, retroId); + } +} diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/RetroTimerStartEvent.java b/src/main/java/io/nickreuter/retroapi/retro/event/RetroTimerStartEvent.java new file mode 100644 index 0000000..1d35b1f --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/RetroTimerStartEvent.java @@ -0,0 +1,21 @@ +package io.nickreuter.retroapi.retro.event; + +import io.nickreuter.retroapi.notification.EventType; +import io.nickreuter.retroapi.notification.event.BaseEvent; + +import java.util.UUID; + +public class RetroTimerStartEvent extends BaseEvent { + private static final String ROUTE_STRING = "/topic/retros.%s.events"; + private final UUID retroId; + + public RetroTimerStartEvent(Object source, Object payload, UUID retroId) { + super(source, EventType.TIMER_START, payload); + this.retroId = retroId; + } + + @Override + public String getRoute() { + return String.format(ROUTE_STRING, retroId); + } +} diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/RetroTimerStopEvent.java b/src/main/java/io/nickreuter/retroapi/retro/event/RetroTimerStopEvent.java new file mode 100644 index 0000000..60b151f --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/RetroTimerStopEvent.java @@ -0,0 +1,21 @@ +package io.nickreuter.retroapi.retro.event; + +import io.nickreuter.retroapi.notification.EventType; +import io.nickreuter.retroapi.notification.event.BaseEvent; + +import java.util.UUID; + +public class RetroTimerStopEvent extends BaseEvent { + private static final String ROUTE_STRING = "/topic/retros.%s.events"; + private final UUID retroId; + + public RetroTimerStopEvent(Object source, Object payload, UUID retroId) { + super(source, EventType.TIMER_STOP, payload); + this.retroId = retroId; + } + + @Override + public String getRoute() { + return String.format(ROUTE_STRING, retroId); + } +} diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/SortRequest.java b/src/main/java/io/nickreuter/retroapi/retro/event/SortRequest.java new file mode 100644 index 0000000..2e2d7a3 --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/SortRequest.java @@ -0,0 +1,3 @@ +package io.nickreuter.retroapi.retro.event; + +public record SortRequest(String column, String direction) {} diff --git a/src/main/java/io/nickreuter/retroapi/retro/event/TimerStartRequest.java b/src/main/java/io/nickreuter/retroapi/retro/event/TimerStartRequest.java new file mode 100644 index 0000000..842e8c9 --- /dev/null +++ b/src/main/java/io/nickreuter/retroapi/retro/event/TimerStartRequest.java @@ -0,0 +1,3 @@ +package io.nickreuter.retroapi.retro.event; + +public record TimerStartRequest(int durationSeconds) {} diff --git a/src/main/java/io/nickreuter/retroapi/retro/thought/ThoughtService.java b/src/main/java/io/nickreuter/retroapi/retro/thought/ThoughtService.java index 30e52b8..36c8e3f 100644 --- a/src/main/java/io/nickreuter/retroapi/retro/thought/ThoughtService.java +++ b/src/main/java/io/nickreuter/retroapi/retro/thought/ThoughtService.java @@ -1,6 +1,6 @@ package io.nickreuter.retroapi.retro.thought; -import io.nickreuter.retroapi.notification.ActionType; +import io.nickreuter.retroapi.notification.EventType; import io.nickreuter.retroapi.notification.event.ThoughtEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @@ -21,7 +21,7 @@ public ThoughtService(ThoughtRepository thoughtRepository, ApplicationEventPubli public ThoughtEntity createThought(UUID retroId, String message, String category) { var savedThought = thoughtRepository.save(ThoughtEntity.from(message, category, retroId)); - applicationEventPublisher.publishEvent(new ThoughtEvent(this, ActionType.CREATE, savedThought, retroId)); + applicationEventPublisher.publishEvent(new ThoughtEvent(this, EventType.CREATE, savedThought, retroId)); return savedThought; } @@ -32,34 +32,34 @@ public Optional getThought(UUID thoughtId) { public void addVote(UUID thoughtId) { thoughtRepository.incrementVotes(thoughtId); var thought = thoughtRepository.findById(thoughtId).orElseThrow(); - applicationEventPublisher.publishEvent(new ThoughtEvent(this, ActionType.UPDATE, thought, thought.getRetroId())); + applicationEventPublisher.publishEvent(new ThoughtEvent(this, EventType.UPDATE, thought, thought.getRetroId())); } public void setCompleted(UUID thoughtId, boolean completed) { var thought = thoughtRepository.findById(thoughtId).orElseThrow(); thought.setCompleted(completed); var updatedThought = thoughtRepository.save(thought); - applicationEventPublisher.publishEvent(new ThoughtEvent(this, ActionType.UPDATE, updatedThought, updatedThought.getRetroId())); + applicationEventPublisher.publishEvent(new ThoughtEvent(this, EventType.UPDATE, updatedThought, updatedThought.getRetroId())); } public void setCategory(UUID thoughtId, String category) { var thought = thoughtRepository.findById(thoughtId).orElseThrow(); thought.setCategory(category); var updatedThought = thoughtRepository.save(thought); - applicationEventPublisher.publishEvent(new ThoughtEvent(this, ActionType.UPDATE, updatedThought, updatedThought.getRetroId())); + applicationEventPublisher.publishEvent(new ThoughtEvent(this, EventType.UPDATE, updatedThought, updatedThought.getRetroId())); } public void setMessage(UUID thoughtId, String message) { var thought = thoughtRepository.findById(thoughtId).orElseThrow(); thought.setMessage(message); var updatedThought = thoughtRepository.save(thought); - applicationEventPublisher.publishEvent(new ThoughtEvent(this, ActionType.UPDATE, updatedThought, updatedThought.getRetroId())); + applicationEventPublisher.publishEvent(new ThoughtEvent(this, EventType.UPDATE, updatedThought, updatedThought.getRetroId())); } public void deleteThought(UUID thoughtId) { var thought = thoughtRepository.findById(thoughtId).orElseThrow(); thoughtRepository.deleteById(thoughtId); - applicationEventPublisher.publishEvent(new ThoughtEvent(this, ActionType.DELETE, thought, thought.getRetroId())); + applicationEventPublisher.publishEvent(new ThoughtEvent(this, EventType.DELETE, thought, thought.getRetroId())); } public List getThoughtsForRetro(UUID retroId) { diff --git a/src/main/java/io/nickreuter/retroapi/team/actionitem/ActionItemService.java b/src/main/java/io/nickreuter/retroapi/team/actionitem/ActionItemService.java index d08c053..b8aad55 100644 --- a/src/main/java/io/nickreuter/retroapi/team/actionitem/ActionItemService.java +++ b/src/main/java/io/nickreuter/retroapi/team/actionitem/ActionItemService.java @@ -1,6 +1,6 @@ package io.nickreuter.retroapi.team.actionitem; -import io.nickreuter.retroapi.notification.ActionType; +import io.nickreuter.retroapi.notification.EventType; import io.nickreuter.retroapi.notification.event.ActionItemEvent; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @@ -25,7 +25,7 @@ public List getActionItemsForTeam(UUID teamId) { public ActionItemEntity createActionItem(String action, String assignee, UUID teamId) { var actionItem = actionItemRepository.save(ActionItemEntity.from(action, assignee, teamId)); - applicationEventPublisher.publishEvent(new ActionItemEvent(this, ActionType.CREATE, actionItem, teamId)); + applicationEventPublisher.publishEvent(new ActionItemEvent(this, EventType.CREATE, actionItem, teamId)); return actionItem; } @@ -33,27 +33,27 @@ public void setAction(UUID actionItemId, String action) { var actionItem = actionItemRepository.findById(actionItemId).orElseThrow(); actionItem.setAction(action); var updatedActionItem = actionItemRepository.save(actionItem); - applicationEventPublisher.publishEvent(new ActionItemEvent(this, ActionType.UPDATE, updatedActionItem, updatedActionItem.getTeamId())); + applicationEventPublisher.publishEvent(new ActionItemEvent(this, EventType.UPDATE, updatedActionItem, updatedActionItem.getTeamId())); } public void setAssignee(UUID actionItemId, String assignee) { var actionItem = actionItemRepository.findById(actionItemId).orElseThrow(); actionItem.setAssignee(assignee); var updatedActionItem = actionItemRepository.save(actionItem); - applicationEventPublisher.publishEvent(new ActionItemEvent(this, ActionType.UPDATE, updatedActionItem, updatedActionItem.getTeamId())); + applicationEventPublisher.publishEvent(new ActionItemEvent(this, EventType.UPDATE, updatedActionItem, updatedActionItem.getTeamId())); } public void setCompleted(UUID actionItemId, boolean completed) { var actionItem = actionItemRepository.findById(actionItemId).orElseThrow(); actionItem.setCompleted(completed); var updatedActionItem = actionItemRepository.save(actionItem); - applicationEventPublisher.publishEvent(new ActionItemEvent(this, ActionType.UPDATE, updatedActionItem, updatedActionItem.getTeamId())); + applicationEventPublisher.publishEvent(new ActionItemEvent(this, EventType.UPDATE, updatedActionItem, updatedActionItem.getTeamId())); } public void deleteActionItem(UUID actionItemId) { var actionItem = actionItemRepository.findById(actionItemId).orElseThrow(); actionItemRepository.delete(actionItem); - applicationEventPublisher.publishEvent(new ActionItemEvent(this, ActionType.DELETE, actionItem, actionItem.getTeamId())); + applicationEventPublisher.publishEvent(new ActionItemEvent(this, EventType.DELETE, actionItem, actionItem.getTeamId())); } public Optional getActionItem(UUID actionItemId) { diff --git a/src/test/java/io/nickreuter/retroapi/notification/WebsocketNotificationServiceTest.java b/src/test/java/io/nickreuter/retroapi/notification/WebsocketNotificationServiceTest.java index ed9bb6b..79b8162 100644 --- a/src/test/java/io/nickreuter/retroapi/notification/WebsocketNotificationServiceTest.java +++ b/src/test/java/io/nickreuter/retroapi/notification/WebsocketNotificationServiceTest.java @@ -18,18 +18,18 @@ class WebsocketNotificationServiceTest { @Test void onApplicationEvent_WhenEventEmitted_SendMessageToWebSocket() throws Exception { var retroId = UUID.randomUUID(); - var event = new ThoughtEvent(this, ActionType.CREATE, null, retroId); + var event = new ThoughtEvent(this, EventType.CREATE, null, retroId); when(objectMapper.writeValueAsString(any())).thenReturn("value"); subject.onApplicationEvent(event); - verify(simpMessagingTemplate).convertAndSend("/topic/%s.thoughts".formatted(retroId), "value"); + verify(simpMessagingTemplate).convertAndSend("/topic/retros.%s.thoughts".formatted(retroId), "value"); } @Test void onApplicationEvent_WhenEventSerializationFails_DoesNotSendMessage() throws Exception { var retroId = UUID.randomUUID(); - var event = new ThoughtEvent(this, ActionType.CREATE, null, retroId); + var event = new ThoughtEvent(this, EventType.CREATE, null, retroId); when(objectMapper.writeValueAsString(any())).thenThrow(JsonProcessingException.class); subject.onApplicationEvent(event); diff --git a/src/test/java/io/nickreuter/retroapi/retro/RetroServiceTest.java b/src/test/java/io/nickreuter/retroapi/retro/RetroServiceTest.java index 0527f7b..375cc5d 100644 --- a/src/test/java/io/nickreuter/retroapi/retro/RetroServiceTest.java +++ b/src/test/java/io/nickreuter/retroapi/retro/RetroServiceTest.java @@ -1,6 +1,6 @@ package io.nickreuter.retroapi.retro; -import io.nickreuter.retroapi.notification.ActionType; +import io.nickreuter.retroapi.notification.EventType; import io.nickreuter.retroapi.notification.event.RetroFinishedEvent; import io.nickreuter.retroapi.retro.template.Category; import io.nickreuter.retroapi.retro.template.Template; @@ -93,8 +93,8 @@ void setFinished_PublishesEvent() throws RetroNotFoundException { var argCaptor = ArgumentCaptor.forClass(RetroFinishedEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.finished".formatted(retroId)); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.UPDATE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/retros.%s.events".formatted(retroId)); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.RETRO_FINISHED); assertThat(argCaptor.getValue().getPayload()).isEqualTo(true); } diff --git a/src/test/java/io/nickreuter/retroapi/retro/event/RetroEventControllerTest.java b/src/test/java/io/nickreuter/retroapi/retro/event/RetroEventControllerTest.java new file mode 100644 index 0000000..ff27ed0 --- /dev/null +++ b/src/test/java/io/nickreuter/retroapi/retro/event/RetroEventControllerTest.java @@ -0,0 +1,249 @@ +package io.nickreuter.retroapi.retro.event; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.nickreuter.retroapi.team.usermapping.UserMappingAuthorizationService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.UUID; + +import static io.nickreuter.retroapi.team.TestAuthenticationCreationService.createAuthentication; +import static org.mockito.Mockito.*; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@AutoConfigureMockMvc +@SpringBootTest +class RetroEventControllerTest { + @MockitoBean + private JwtDecoder jwtDecoder; + @MockitoBean + private RetroEventService retroEventService; + @MockitoBean + private UserMappingAuthorizationService userMappingAuthorizationService; + + @Autowired + private MockMvc mockMvc; + @Autowired + private ObjectMapper objectMapper; + + private static final String BASE_URL = "/api/teams/%s/retros/%s/events"; + + // Timer Start + @Test + void startTimer_Returns200() throws Exception { + var teamId = UUID.randomUUID(); + var retroId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(true); + mockMvc.perform(post((BASE_URL + "/timer-start").formatted(teamId, retroId)) + .with(jwt()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new TimerStartRequest(300)))) + .andExpect(status().isOk()); + verify(retroEventService).publishTimerStart(retroId, 300); + } + + @Test + void startTimer_WhenAnonymous_Returns401() throws Exception { + mockMvc.perform(post((BASE_URL + "/timer-start").formatted(UUID.randomUUID(), UUID.randomUUID())) + .with(anonymous()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new TimerStartRequest(300)))) + .andExpect(status().isUnauthorized()); + } + + @Test + void startTimer_WhenNotMember_Returns403() throws Exception { + var teamId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(false); + mockMvc.perform(post((BASE_URL + "/timer-start").formatted(teamId, UUID.randomUUID())) + .with(jwt()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new TimerStartRequest(300)))) + .andExpect(status().isForbidden()); + } + + // Timer Stop + @Test + void stopTimer_Returns200() throws Exception { + var teamId = UUID.randomUUID(); + var retroId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(true); + mockMvc.perform(post((BASE_URL + "/timer-stop").formatted(teamId, retroId)) + .with(jwt()) + .with(csrf())) + .andExpect(status().isOk()); + verify(retroEventService).publishTimerStop(retroId); + } + + @Test + void stopTimer_WhenAnonymous_Returns401() throws Exception { + mockMvc.perform(post((BASE_URL + "/timer-stop").formatted(UUID.randomUUID(), UUID.randomUUID())) + .with(anonymous()) + .with(csrf())) + .andExpect(status().isUnauthorized()); + } + + @Test + void stopTimer_WhenNotMember_Returns403() throws Exception { + var teamId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(false); + mockMvc.perform(post((BASE_URL + "/timer-stop").formatted(teamId, UUID.randomUUID())) + .with(jwt()) + .with(csrf())) + .andExpect(status().isForbidden()); + } + + // Focus + @Test + void focusThought_Returns200() throws Exception { + var teamId = UUID.randomUUID(); + var retroId = UUID.randomUUID(); + var thoughtId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(true); + mockMvc.perform(post((BASE_URL + "/focus").formatted(teamId, retroId)) + .with(jwt()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new FocusRequest(thoughtId)))) + .andExpect(status().isOk()); + verify(retroEventService).publishFocus(retroId, thoughtId); + } + + @Test + void focusThought_WhenAnonymous_Returns401() throws Exception { + mockMvc.perform(post((BASE_URL + "/focus").formatted(UUID.randomUUID(), UUID.randomUUID())) + .with(anonymous()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new FocusRequest(UUID.randomUUID())))) + .andExpect(status().isUnauthorized()); + } + + @Test + void focusThought_WhenNotMember_Returns403() throws Exception { + var teamId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(false); + mockMvc.perform(post((BASE_URL + "/focus").formatted(teamId, UUID.randomUUID())) + .with(jwt()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new FocusRequest(UUID.randomUUID())))) + .andExpect(status().isForbidden()); + } + + // Focus Clear + @Test + void clearFocus_Returns200() throws Exception { + var teamId = UUID.randomUUID(); + var retroId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(true); + mockMvc.perform(post((BASE_URL + "/focus-clear").formatted(teamId, retroId)) + .with(jwt()) + .with(csrf())) + .andExpect(status().isOk()); + verify(retroEventService).publishFocusClear(retroId); + } + + @Test + void clearFocus_WhenAnonymous_Returns401() throws Exception { + mockMvc.perform(post((BASE_URL + "/focus-clear").formatted(UUID.randomUUID(), UUID.randomUUID())) + .with(anonymous()) + .with(csrf())) + .andExpect(status().isUnauthorized()); + } + + @Test + void clearFocus_WhenNotMember_Returns403() throws Exception { + var teamId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(false); + mockMvc.perform(post((BASE_URL + "/focus-clear").formatted(teamId, UUID.randomUUID())) + .with(jwt()) + .with(csrf())) + .andExpect(status().isForbidden()); + } + + // Sort + @Test + void sortColumn_Returns200() throws Exception { + var teamId = UUID.randomUUID(); + var retroId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(true); + mockMvc.perform(post((BASE_URL + "/sort").formatted(teamId, retroId)) + .with(jwt()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new SortRequest("votes", "desc")))) + .andExpect(status().isOk()); + verify(retroEventService).publishSort(retroId, "votes", "desc"); + } + + @Test + void sortColumn_WhenAnonymous_Returns401() throws Exception { + mockMvc.perform(post((BASE_URL + "/sort").formatted(UUID.randomUUID(), UUID.randomUUID())) + .with(anonymous()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new SortRequest("votes", "desc")))) + .andExpect(status().isUnauthorized()); + } + + @Test + void sortColumn_WhenNotMember_Returns403() throws Exception { + var teamId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(false); + mockMvc.perform(post((BASE_URL + "/sort").formatted(teamId, UUID.randomUUID())) + .with(jwt()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new SortRequest("votes", "desc")))) + .andExpect(status().isForbidden()); + } + + // Phase + @Test + void changePhase_Returns200() throws Exception { + var teamId = UUID.randomUUID(); + var retroId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(true); + mockMvc.perform(post((BASE_URL + "/phase").formatted(teamId, retroId)) + .with(jwt()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new PhaseRequest("voting")))) + .andExpect(status().isOk()); + verify(retroEventService).publishPhase(retroId, "voting"); + } + + @Test + void changePhase_WhenAnonymous_Returns401() throws Exception { + mockMvc.perform(post((BASE_URL + "/phase").formatted(UUID.randomUUID(), UUID.randomUUID())) + .with(anonymous()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new PhaseRequest("voting")))) + .andExpect(status().isUnauthorized()); + } + + @Test + void changePhase_WhenNotMember_Returns403() throws Exception { + var teamId = UUID.randomUUID(); + when(userMappingAuthorizationService.isUserMemberOfTeam(createAuthentication(), teamId)).thenReturn(false); + mockMvc.perform(post((BASE_URL + "/phase").formatted(teamId, UUID.randomUUID())) + .with(jwt()) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(new PhaseRequest("voting")))) + .andExpect(status().isForbidden()); + } +} diff --git a/src/test/java/io/nickreuter/retroapi/retro/event/RetroEventServiceTest.java b/src/test/java/io/nickreuter/retroapi/retro/event/RetroEventServiceTest.java new file mode 100644 index 0000000..7557875 --- /dev/null +++ b/src/test/java/io/nickreuter/retroapi/retro/event/RetroEventServiceTest.java @@ -0,0 +1,83 @@ +package io.nickreuter.retroapi.retro.event; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.context.ApplicationEventPublisher; + +import java.util.UUID; + +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.verify; + +@ExtendWith(MockitoExtension.class) +class RetroEventServiceTest { + @Mock + private ApplicationEventPublisher applicationEventPublisher; + + @InjectMocks + private RetroEventService retroEventService; + + @Test + void publishTimerStart_PublishesRetroTimerStartEvent() { + var retroId = UUID.randomUUID(); + retroEventService.publishTimerStart(retroId, 300); + verify(applicationEventPublisher).publishEvent(argThat(event -> + event instanceof RetroTimerStartEvent e && + e.getRoute().equals("/topic/retros.%s.events".formatted(retroId)) + )); + } + + @Test + void publishTimerStop_PublishesRetroTimerStopEvent() { + var retroId = UUID.randomUUID(); + retroEventService.publishTimerStop(retroId); + verify(applicationEventPublisher).publishEvent(argThat(event -> + event instanceof RetroTimerStopEvent e && + e.getRoute().equals("/topic/retros.%s.events".formatted(retroId)) + )); + } + + @Test + void publishFocus_PublishesRetroFocusEvent() { + var retroId = UUID.randomUUID(); + var thoughtId = UUID.randomUUID(); + retroEventService.publishFocus(retroId, thoughtId); + verify(applicationEventPublisher).publishEvent(argThat(event -> + event instanceof RetroFocusEvent e && + e.getRoute().equals("/topic/retros.%s.events".formatted(retroId)) + )); + } + + @Test + void publishFocusClear_PublishesRetroFocusClearEvent() { + var retroId = UUID.randomUUID(); + retroEventService.publishFocusClear(retroId); + verify(applicationEventPublisher).publishEvent(argThat(event -> + event instanceof RetroFocusClearEvent e && + e.getRoute().equals("/topic/retros.%s.events".formatted(retroId)) + )); + } + + @Test + void publishSort_PublishesRetroSortEvent() { + var retroId = UUID.randomUUID(); + retroEventService.publishSort(retroId, "votes", "desc"); + verify(applicationEventPublisher).publishEvent(argThat(event -> + event instanceof RetroSortEvent e && + e.getRoute().equals("/topic/retros.%s.events".formatted(retroId)) + )); + } + + @Test + void publishPhase_PublishesRetroPhaseEvent() { + var retroId = UUID.randomUUID(); + retroEventService.publishPhase(retroId, "voting"); + verify(applicationEventPublisher).publishEvent(argThat(event -> + event instanceof RetroPhaseEvent e && + e.getRoute().equals("/topic/retros.%s.events".formatted(retroId)) + )); + } +} diff --git a/src/test/java/io/nickreuter/retroapi/retro/thought/ThoughtServiceTest.java b/src/test/java/io/nickreuter/retroapi/retro/thought/ThoughtServiceTest.java index 95e40d6..c3fe98f 100644 --- a/src/test/java/io/nickreuter/retroapi/retro/thought/ThoughtServiceTest.java +++ b/src/test/java/io/nickreuter/retroapi/retro/thought/ThoughtServiceTest.java @@ -1,6 +1,6 @@ package io.nickreuter.retroapi.retro.thought; -import io.nickreuter.retroapi.notification.ActionType; +import io.nickreuter.retroapi.notification.EventType; import io.nickreuter.retroapi.notification.event.ThoughtEvent; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -61,8 +61,8 @@ void createThought_SendsEventToApplicationEventPublisher() { var argCaptor = ArgumentCaptor.forClass(ThoughtEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.thoughts".formatted(retroId)); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.CREATE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/retros.%s.thoughts".formatted(retroId)); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.CREATE); assertThat(argCaptor.getValue().getPayload()).isEqualTo(expected); } @@ -104,8 +104,8 @@ void addVote_WhenCountUpdated_PublishesEvent() { var argCaptor = ArgumentCaptor.forClass(ThoughtEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.thoughts".formatted(expected.getRetroId())); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.UPDATE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/retros.%s.thoughts".formatted(expected.getRetroId())); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.UPDATE); assertThat(argCaptor.getValue().getPayload()).isEqualTo(expected); } @@ -135,8 +135,8 @@ void setCompleted_PublishesEvent() { var argCaptor = ArgumentCaptor.forClass(ThoughtEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.thoughts".formatted(expected.getRetroId())); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.UPDATE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/retros.%s.thoughts".formatted(expected.getRetroId())); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.UPDATE); assertThat(argCaptor.getValue().getPayload()).isEqualTo(expected); } @@ -167,8 +167,8 @@ void setCategory_PublishesEvent() { var argCaptor = ArgumentCaptor.forClass(ThoughtEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.thoughts".formatted(expected.getRetroId())); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.UPDATE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/retros.%s.thoughts".formatted(expected.getRetroId())); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.UPDATE); assertThat(argCaptor.getValue().getPayload()).isEqualTo(expected); } @@ -199,8 +199,8 @@ void setMessage_PublishesEvent() { var argCaptor = ArgumentCaptor.forClass(ThoughtEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.thoughts".formatted(expected.getRetroId())); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.UPDATE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/retros.%s.thoughts".formatted(expected.getRetroId())); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.UPDATE); assertThat(argCaptor.getValue().getPayload()).isEqualTo(expected); } @@ -225,8 +225,8 @@ void deleteThought_PublishesEvent() { var argCaptor = ArgumentCaptor.forClass(ThoughtEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.thoughts".formatted(savedThought.getRetroId())); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.DELETE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/retros.%s.thoughts".formatted(savedThought.getRetroId())); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.DELETE); assertThat(argCaptor.getValue().getPayload()).isEqualTo(savedThought); } } \ No newline at end of file diff --git a/src/test/java/io/nickreuter/retroapi/team/actionitem/ActionItemServiceTest.java b/src/test/java/io/nickreuter/retroapi/team/actionitem/ActionItemServiceTest.java index e4fcf30..727acd3 100644 --- a/src/test/java/io/nickreuter/retroapi/team/actionitem/ActionItemServiceTest.java +++ b/src/test/java/io/nickreuter/retroapi/team/actionitem/ActionItemServiceTest.java @@ -1,6 +1,6 @@ package io.nickreuter.retroapi.team.actionitem; -import io.nickreuter.retroapi.notification.ActionType; +import io.nickreuter.retroapi.notification.EventType; import io.nickreuter.retroapi.notification.event.ActionItemEvent; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; @@ -62,8 +62,8 @@ void createActionItem_PublishesEvent() { var argCaptor = ArgumentCaptor.forClass(ActionItemEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.action-items".formatted(teamId)); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.CREATE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/teams.%s.action-items".formatted(teamId)); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.CREATE); assertThat(argCaptor.getValue().getPayload()).isEqualTo(expected); } @@ -102,8 +102,8 @@ void setAction_PublishesEvent() { var argCaptor = ArgumentCaptor.forClass(ActionItemEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.action-items".formatted(teamId)); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.UPDATE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/teams.%s.action-items".formatted(teamId)); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.UPDATE); assertThat(argCaptor.getValue().getPayload()).isEqualTo(expected); } @@ -142,8 +142,8 @@ void setAssignee_PublishesEvent() { var argCaptor = ArgumentCaptor.forClass(ActionItemEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.action-items".formatted(teamId)); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.UPDATE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/teams.%s.action-items".formatted(teamId)); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.UPDATE); assertThat(argCaptor.getValue().getPayload()).isEqualTo(expected); } @@ -182,8 +182,8 @@ void setCompleted_PublishesEvent() { var argCaptor = ArgumentCaptor.forClass(ActionItemEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.action-items".formatted(teamId)); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.UPDATE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/teams.%s.action-items".formatted(teamId)); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.UPDATE); assertThat(argCaptor.getValue().getPayload()).isEqualTo(expected); } @@ -209,8 +209,8 @@ void deleteActionItem_PublishesEvent() { var argCaptor = ArgumentCaptor.forClass(ActionItemEvent.class); verify(applicationEventPublisher).publishEvent(argCaptor.capture()); - assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/%s.action-items".formatted(teamId)); - assertThat(argCaptor.getValue().getActionType()).isEqualTo(ActionType.DELETE); + assertThat(argCaptor.getValue().getRoute()).isEqualTo("/topic/teams.%s.action-items".formatted(teamId)); + assertThat(argCaptor.getValue().getEventType()).isEqualTo(EventType.DELETE); assertThat(argCaptor.getValue().getPayload()).isEqualTo(savedActionItem); }