Skip to content

Commit 77fdbc8

Browse files
committed
Add check for alignment in same team
1 parent 3478e6f commit 77fdbc8

File tree

4 files changed

+112
-4
lines changed

4 files changed

+112
-4
lines changed

backend/src/main/java/ch/puzzle/okr/ErrorKey.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@ public enum ErrorKey {
44
ATTRIBUTE_NULL, ATTRIBUTE_CHANGED, ATTRIBUTE_SET_FORBIDDEN, ATTRIBUTE_NOT_SET, ATTRIBUTE_CANNOT_CHANGE,
55
ATTRIBUTE_MUST_BE_DRAFT, KEY_RESULT_CONVERSION, ALREADY_EXISTS_SAME_NAME, CONVERT_TOKEN, DATA_HAS_BEEN_UPDATED,
66
MODEL_NULL, MODEL_WITH_ID_NOT_FOUND, NOT_AUTHORIZED_TO_READ, NOT_AUTHORIZED_TO_WRITE, NOT_AUTHORIZED_TO_DELETE,
7-
TOKEN_NULL, NOT_LINK_YOURSELF, ALIGNMENT_ALREADY_EXISTS
7+
TOKEN_NULL, NOT_LINK_YOURSELF, NOT_LINK_IN_SAME_TEAM, ALIGNMENT_ALREADY_EXISTS
88
}

backend/src/main/java/ch/puzzle/okr/service/validation/AlignmentValidationService.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
import ch.puzzle.okr.ErrorKey;
44
import ch.puzzle.okr.exception.OkrResponseStatusException;
5+
import ch.puzzle.okr.models.Team;
56
import ch.puzzle.okr.models.alignment.Alignment;
67
import ch.puzzle.okr.models.alignment.KeyResultAlignment;
78
import ch.puzzle.okr.models.alignment.ObjectiveAlignment;
89
import ch.puzzle.okr.repository.AlignmentRepository;
910
import ch.puzzle.okr.service.persistence.AlignmentPersistenceService;
11+
import ch.puzzle.okr.service.persistence.TeamPersistenceService;
1012
import org.springframework.http.HttpStatus;
1113
import org.springframework.stereotype.Service;
1214

@@ -18,10 +20,13 @@ public class AlignmentValidationService
1820
extends ValidationBase<Alignment, Long, AlignmentRepository, AlignmentPersistenceService> {
1921

2022
private final AlignmentPersistenceService alignmentPersistenceService;
23+
private final TeamPersistenceService teamPersistenceService;
2124

22-
public AlignmentValidationService(AlignmentPersistenceService alignmentPersistenceService) {
25+
public AlignmentValidationService(AlignmentPersistenceService alignmentPersistenceService,
26+
TeamPersistenceService teamPersistenceService) {
2327
super(alignmentPersistenceService);
2428
this.alignmentPersistenceService = alignmentPersistenceService;
29+
this.teamPersistenceService = teamPersistenceService;
2530
}
2631

2732
@Override
@@ -30,6 +35,7 @@ public void validateOnCreate(Alignment model) {
3035
throwExceptionWhenIdIsNotNull(model.getId());
3136
throwExceptionWhenAlignedObjectIsNull(model);
3237
throwExceptionWhenAlignedIdIsSameAsTargetId(model);
38+
throwExceptionWhenAlignmentIsInSameTeam(model);
3339
throwExceptionWhenAlignedObjectiveAlreadyExists(model);
3440
validate(model);
3541
}
@@ -40,6 +46,7 @@ public void validateOnUpdate(Long id, Alignment model) {
4046
throwExceptionWhenIdIsNull(model.getId());
4147
throwExceptionWhenAlignedObjectIsNull(model);
4248
throwExceptionWhenAlignedIdIsSameAsTargetId(model);
49+
throwExceptionWhenAlignmentIsInSameTeam(model);
4350
validate(model);
4451
}
4552

@@ -60,6 +67,23 @@ private void throwExceptionWhenAlignedObjectIsNull(Alignment model) {
6067
}
6168
}
6269

70+
private void throwExceptionWhenAlignmentIsInSameTeam(Alignment model) {
71+
Team alignedTeam = teamPersistenceService.findById(model.getAlignedObjective().getTeam().getId());
72+
Team targetTeam = null;
73+
74+
if (model instanceof ObjectiveAlignment objectiveAlignment) {
75+
targetTeam = teamPersistenceService.findById(objectiveAlignment.getAlignmentTarget().getTeam().getId());
76+
} else if (model instanceof KeyResultAlignment keyResultAlignment) {
77+
targetTeam = teamPersistenceService
78+
.findById(keyResultAlignment.getAlignmentTarget().getObjective().getTeam().getId());
79+
}
80+
81+
if (alignedTeam.equals(targetTeam)) {
82+
throw new OkrResponseStatusException(HttpStatus.BAD_REQUEST, ErrorKey.NOT_LINK_IN_SAME_TEAM,
83+
List.of("teamId", targetTeam.getId()));
84+
}
85+
}
86+
6387
private void throwExceptionWhenAlignedIdIsSameAsTargetId(Alignment model) {
6488
if (model instanceof ObjectiveAlignment objectiveAlignment) {
6589
if (Objects.equals(objectiveAlignment.getAlignedObjective().getId(),

backend/src/test/java/ch/puzzle/okr/service/validation/AlignmentValidationServiceTest.java

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
import ch.puzzle.okr.dto.ErrorDto;
55
import ch.puzzle.okr.exception.OkrResponseStatusException;
66
import ch.puzzle.okr.models.Objective;
7+
import ch.puzzle.okr.models.Team;
78
import ch.puzzle.okr.models.alignment.KeyResultAlignment;
89
import ch.puzzle.okr.models.alignment.ObjectiveAlignment;
910
import ch.puzzle.okr.models.keyresult.KeyResult;
1011
import ch.puzzle.okr.models.keyresult.KeyResultMetric;
1112
import ch.puzzle.okr.service.persistence.AlignmentPersistenceService;
13+
import ch.puzzle.okr.service.persistence.TeamPersistenceService;
1214
import org.junit.jupiter.api.BeforeEach;
1315
import org.junit.jupiter.api.Test;
1416
import org.junit.jupiter.api.extension.ExtendWith;
@@ -31,12 +33,18 @@ class AlignmentValidationServiceTest {
3133

3234
@Mock
3335
AlignmentPersistenceService alignmentPersistenceService;
36+
@Mock
37+
TeamPersistenceService teamPersistenceService;
3438
@Spy
3539
@InjectMocks
3640
private AlignmentValidationService validator;
3741

38-
Objective objective1 = Objective.Builder.builder().withId(5L).withTitle("Objective 1").withState(DRAFT).build();
39-
Objective objective2 = Objective.Builder.builder().withId(8L).withTitle("Objective 2").withState(DRAFT).build();
42+
Team team1 = Team.Builder.builder().withId(1L).withName("Puzzle ITC").build();
43+
Team team2 = Team.Builder.builder().withId(2L).withName("BBT").build();
44+
Objective objective1 = Objective.Builder.builder().withId(5L).withTitle("Objective 1").withTeam(team1)
45+
.withState(DRAFT).build();
46+
Objective objective2 = Objective.Builder.builder().withId(8L).withTitle("Objective 2").withTeam(team2)
47+
.withState(DRAFT).build();
4048
Objective objective3 = Objective.Builder.builder().withId(10L).withTitle("Objective 3").withState(DRAFT).build();
4149
KeyResult metricKeyResult = KeyResultMetric.Builder.builder().withId(5L).withTitle("KR Title 1").build();
4250
ObjectiveAlignment objectiveALignment = ObjectiveAlignment.Builder.builder().withId(1L)
@@ -74,6 +82,8 @@ void validateOnGetShouldThrowExceptionIfIdIsNull() {
7482
@Test
7583
void validateOnCreateShouldBeSuccessfulWhenAlignmentIsValid() {
7684
when(alignmentPersistenceService.findByAlignedObjectiveId(anyLong())).thenReturn(null);
85+
when(teamPersistenceService.findById(1L)).thenReturn(team1);
86+
when(teamPersistenceService.findById(2L)).thenReturn(team2);
7787

7888
validator.validateOnCreate(createAlignment);
7989

@@ -165,9 +175,45 @@ void validateOnCreateShouldThrowExceptionWhenAlignedIdIsSameAsTargetId() {
165175
assertTrue(TestHelper.getAllErrorKeys(expectedErrors).contains(exception.getReason()));
166176
}
167177

178+
@Test
179+
void validateOnCreateShouldThrowExceptionWhenAlignmentIsInSameTeamObjective() {
180+
when(teamPersistenceService.findById(2L)).thenReturn(team2);
181+
Objective objective = objective1;
182+
objective.setTeam(team2);
183+
ObjectiveAlignment objectiveAlignment = ObjectiveAlignment.Builder.builder().withAlignedObjective(objective)
184+
.withTargetObjective(objective2).build();
185+
186+
OkrResponseStatusException exception = assertThrows(OkrResponseStatusException.class,
187+
() -> validator.validateOnCreate(objectiveAlignment));
188+
189+
List<ErrorDto> expectedErrors = List.of(new ErrorDto("NOT_LINK_IN_SAME_TEAM", List.of("teamId", "2")));
190+
191+
assertEquals(BAD_REQUEST, exception.getStatusCode());
192+
assertThat(expectedErrors).hasSameElementsAs(exception.getErrors());
193+
assertTrue(TestHelper.getAllErrorKeys(expectedErrors).contains(exception.getReason()));
194+
}
195+
196+
@Test
197+
void validateOnCreateShouldThrowExceptionWhenAlignmentIsInSameTeamKeyResult() {
198+
when(teamPersistenceService.findById(1L)).thenReturn(team1);
199+
KeyResult keyResult = KeyResultMetric.Builder.builder().withId(3L).withTitle("KeyResult 1").withObjective(objective1).build();
200+
KeyResultAlignment keyResultAlignment1 = KeyResultAlignment.Builder.builder().withAlignedObjective(objective1).withTargetKeyResult(keyResult).build();
201+
202+
OkrResponseStatusException exception = assertThrows(OkrResponseStatusException.class,
203+
() -> validator.validateOnCreate(keyResultAlignment1));
204+
205+
List<ErrorDto> expectedErrors = List.of(new ErrorDto("NOT_LINK_IN_SAME_TEAM", List.of("teamId", "1")));
206+
207+
assertEquals(BAD_REQUEST, exception.getStatusCode());
208+
assertThat(expectedErrors).hasSameElementsAs(exception.getErrors());
209+
assertTrue(TestHelper.getAllErrorKeys(expectedErrors).contains(exception.getReason()));
210+
}
211+
168212
@Test
169213
void validateOnCreateShouldThrowExceptionWhenAlignedObjectiveAlreadyExists() {
170214
when(alignmentPersistenceService.findByAlignedObjectiveId(anyLong())).thenReturn(objectiveALignment);
215+
when(teamPersistenceService.findById(1L)).thenReturn(team1);
216+
when(teamPersistenceService.findById(2L)).thenReturn(team2);
171217

172218
ObjectiveAlignment createAlignment = ObjectiveAlignment.Builder.builder().withAlignedObjective(objective1).withTargetObjective(objective2).build();
173219

@@ -183,6 +229,9 @@ void validateOnCreateShouldThrowExceptionWhenAlignedObjectiveAlreadyExists() {
183229

184230
@Test
185231
void validateOnUpdateShouldBeSuccessfulWhenAlignmentIsValid() {
232+
when(teamPersistenceService.findById(1L)).thenReturn(team1);
233+
when(teamPersistenceService.findById(2L)).thenReturn(team2);
234+
186235
validator.validateOnUpdate(objectiveALignment.getId(), objectiveALignment);
187236

188237
verify(validator, times(1)).throwExceptionWhenModelIsNull(objectiveALignment);
@@ -274,6 +323,40 @@ void validateOnUpdateShouldThrowExceptionWhenAlignedIdIsSameAsTargetId() {
274323
assertTrue(TestHelper.getAllErrorKeys(expectedErrors).contains(exception.getReason()));
275324
}
276325

326+
@Test
327+
void validateOnUpdateShouldThrowExceptionWhenAlignmentIsInSameTeamObjective() {
328+
when(teamPersistenceService.findById(2L)).thenReturn(team2);
329+
Objective objective = objective1;
330+
objective.setTeam(team2);
331+
ObjectiveAlignment objectiveAlignment = ObjectiveAlignment.Builder.builder().withId(3L)
332+
.withAlignedObjective(objective).withTargetObjective(objective2).build();
333+
334+
OkrResponseStatusException exception = assertThrows(OkrResponseStatusException.class,
335+
() -> validator.validateOnUpdate(2L, objectiveAlignment));
336+
337+
List<ErrorDto> expectedErrors = List.of(new ErrorDto("NOT_LINK_IN_SAME_TEAM", List.of("teamId", "2")));
338+
339+
assertEquals(BAD_REQUEST, exception.getStatusCode());
340+
assertThat(expectedErrors).hasSameElementsAs(exception.getErrors());
341+
assertTrue(TestHelper.getAllErrorKeys(expectedErrors).contains(exception.getReason()));
342+
}
343+
344+
@Test
345+
void validateOnUpdateShouldThrowExceptionWhenAlignmentIsInSameTeamKeyResult() {
346+
when(teamPersistenceService.findById(1L)).thenReturn(team1);
347+
KeyResult keyResult = KeyResultMetric.Builder.builder().withId(3L).withTitle("KeyResult 1").withObjective(objective1).build();
348+
KeyResultAlignment keyResultAlignment1 = KeyResultAlignment.Builder.builder().withId(2L).withAlignedObjective(objective1).withTargetKeyResult(keyResult).build();
349+
350+
OkrResponseStatusException exception = assertThrows(OkrResponseStatusException.class,
351+
() -> validator.validateOnUpdate(2L, keyResultAlignment1));
352+
353+
List<ErrorDto> expectedErrors = List.of(new ErrorDto("NOT_LINK_IN_SAME_TEAM", List.of("teamId", "1")));
354+
355+
assertEquals(BAD_REQUEST, exception.getStatusCode());
356+
assertThat(expectedErrors).hasSameElementsAs(exception.getErrors());
357+
assertTrue(TestHelper.getAllErrorKeys(expectedErrors).contains(exception.getReason()));
358+
}
359+
277360
@Test
278361
void validateOnDeleteShouldBeSuccessfulWhenValidAlignmentId() {
279362
validator.validateOnDelete(3L);

frontend/src/assets/i18n/de.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
"TOKEN_NULL": "Das erhaltene Token ist null.",
5656
"ILLEGAL_CHANGE_OBJECTIVE_QUARTER": "Element kann nicht in ein anderes Quartal verlegt werden.",
5757
"NOT_LINK_YOURSELF": "Das Objective kann nicht auf sich selbst zeigen.",
58+
"NOT_LINK_IN_SAME_TEAM": "Das Objective kann nicht auf ein Objekt im selben Team zeigen.",
5859
"ALIGNMENT_ALREADY_EXISTS": "Es existiert bereits ein Alignment ausgehend vom Objective mit der ID {1}."
5960
},
6061
"SUCCESS": {

0 commit comments

Comments
 (0)