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

Feature/614 duplicate selected keyresults #1216

Merged
merged 36 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
1d56786
create new endpoint in Objectivecontroller
nevio18324 Nov 25, 2024
9e11b19
crate endpoint for getAllKeyResultsById
nevio18324 Nov 26, 2024
be28fc3
modify duplicate e2e to accept new duplicateObjectDto now only select…
nevio18324 Nov 26, 2024
095c0f6
create new DuplicateObjectiveDto
nevio18324 Nov 26, 2024
d07ec38
implement new duplication to frontend
nevio18324 Nov 26, 2024
c7ddfa5
remove files added accidentally
nevio18324 Nov 26, 2024
1d6e48a
change duplicateObjective type to record instead of class
nevio18324 Nov 26, 2024
757d311
fix bug with id of objective already being defined when trying to dup…
nevio18324 Nov 26, 2024
a393169
fix bug that you couldnt edit objectives anymore
nevio18324 Nov 26, 2024
2ebe457
fix bug that you can't add objectives anymore
nevio18324 Nov 26, 2024
8f2f2e1
Fix small typo
ManuelMoeri Nov 27, 2024
45f4b0c
Reset run config
ManuelMoeri Nov 27, 2024
3cd2323
Fix behaviour of duplicating objectives and small typo
ManuelMoeri Nov 28, 2024
eeaf7a2
Fix logic with creating and duplicating objective
ManuelMoeri Nov 28, 2024
9bbed45
Implement functionality to only show text at desired time and try to …
ManuelMoeri Nov 28, 2024
909e199
Fix failing method calls for tests in backend
ManuelMoeri Nov 29, 2024
f5c2bd5
Cleanup ngOnInit in the objective-form component
ManuelMoeri Nov 29, 2024
4be6317
Fix backend tests
ManuelMoeri Nov 29, 2024
996c28d
Fix frontend tests
ManuelMoeri Nov 29, 2024
5be2334
Reset ngOnInit since it caused a few problems and fix broken TestData
ManuelMoeri Nov 29, 2024
f2ff856
Add method for e2e testing and first two e2e tests. Second one is not…
ManuelMoeri Dec 2, 2024
2465d07
[FM] Automated formating frontend
actions-user Dec 2, 2024
5f2ec90
make all objectiveTests work again except duplication
nevio18324 Dec 3, 2024
9385826
Finish e2e tests for duplicating
ManuelMoeri Dec 4, 2024
e4114e1
Add e2e test for duplicating a objective with no keyresults
ManuelMoeri Dec 9, 2024
198760f
Fix integration test
MasterEvarior Dec 11, 2024
492b109
Add missing service tests for newly created methods
ManuelMoeri Dec 11, 2024
534ec7a
Cleanup ngOnInit a bit
ManuelMoeri Dec 11, 2024
30765c8
Add comments and two small tests for ts
ManuelMoeri Dec 11, 2024
bfa8ed8
Add more descriptive naming in describe
ManuelMoeri Dec 12, 2024
2f1ba0d
Fix grammar in controller endpoint
ManuelMoeri Dec 12, 2024
ab5ba4d
Clenup cypress helper and use variable in styles
ManuelMoeri Dec 12, 2024
491ba5f
Remove not needed method
ManuelMoeri Dec 12, 2024
8274aea
Fix alignment, truncating of text and add tooltip
ManuelMoeri Dec 13, 2024
8886046
Set padding to 0 to align correctly
ManuelMoeri Dec 13, 2024
2093407
Fix color from failed rebase
ManuelMoeri Dec 13, 2024
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
@@ -1,8 +1,15 @@
package ch.puzzle.okr.controller;

import ch.puzzle.okr.dto.checkin.CheckInDto;
import ch.puzzle.okr.dto.keyresult.KeyResultDto;
import ch.puzzle.okr.dto.DuplicateObjectiveDto;
import ch.puzzle.okr.dto.ObjectiveDto;
import ch.puzzle.okr.mapper.ObjectiveMapper;
import ch.puzzle.okr.mapper.keyresult.KeyResultMapper;
import ch.puzzle.okr.models.Action;
import ch.puzzle.okr.models.Objective;
import ch.puzzle.okr.models.keyresult.KeyResult;
import ch.puzzle.okr.service.authorization.ActionAuthorizationService;
import ch.puzzle.okr.service.authorization.ObjectiveAuthorizationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand All @@ -14,6 +21,8 @@
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

import static org.springframework.http.HttpStatus.IM_USED;
import static org.springframework.http.HttpStatus.OK;

Expand All @@ -22,11 +31,16 @@
public class ObjectiveController {
private final ObjectiveAuthorizationService objectiveAuthorizationService;
private final ObjectiveMapper objectiveMapper;
private final KeyResultMapper keyResultMapper;
private final ActionAuthorizationService actionAuthorizationService;

public ObjectiveController(ObjectiveAuthorizationService objectiveAuthorizationService,
ObjectiveMapper objectiveMapper) {
ObjectiveMapper objectiveMapper, KeyResultMapper keyResultMapper,
ActionAuthorizationService actionAuthorizationService) {
this.objectiveAuthorizationService = objectiveAuthorizationService;
this.objectiveMapper = objectiveMapper;
this.keyResultMapper = keyResultMapper;
this.actionAuthorizationService = actionAuthorizationService;
}

@Operation(summary = "Get Objective", description = "Get an Objective by ID")
Expand All @@ -42,6 +56,22 @@ public ResponseEntity<ObjectiveDto> getObjective(
.body(objectiveMapper.toDto(objectiveAuthorizationService.getEntityById(id)));
}

@Operation(summary = "Get KeyResults from Objective", description = "Get all KeyResults from one Objective by ObjectiveId.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Returned all KeyResults from Objective.", content = {
@Content(mediaType = "application/json", schema = @Schema(implementation = CheckInDto.class)) }),
@ApiResponse(responseCode = "401", description = "Not authorized to read KeyResults from an Objective", content = @Content),
@ApiResponse(responseCode = "404", description = "Did not find an Objective with the specified ID to get KeyResults from.", content = @Content) })
@GetMapping("/{id}/keyResults")
public ResponseEntity<List<KeyResultDto>> getKeyResultsFromObjective(
@Parameter(description = "The ID for getting all KeyResults of an Objective", required = true) @PathVariable long id) {
return ResponseEntity.status(OK)
.body(objectiveAuthorizationService.getAllKeyResultsByObjective(id).stream().map(keyResult -> {
List<Action> actionList = actionAuthorizationService.getActionsByKeyResult(keyResult);
return keyResultMapper.toDto(keyResult, actionList);
}).toList());
}

@Operation(summary = "Delete Objective by ID", description = "Delete Objective by ID")
@ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Deleted Objective by ID"),
@ApiResponse(responseCode = "401", description = "Not authorized to delete an Objective", content = @Content),
Expand Down Expand Up @@ -72,10 +102,12 @@ public ResponseEntity<ObjectiveDto> createObjective(
@PostMapping("/{id}")
public ResponseEntity<ObjectiveDto> duplicateObjective(
@Parameter(description = "The ID for duplicating an Objective.", required = true) @PathVariable Long id,
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "The Objective which should be duplicated as json", required = true) @RequestBody ObjectiveDto objectiveDTO) {
Objective objective = objectiveMapper.toObjective(objectiveDTO);
@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "The Objective which should be duplicated as JSON", required = true) @RequestBody DuplicateObjectiveDto duplicateObjectiveDto) {
Objective objective = objectiveMapper.toObjective(duplicateObjectiveDto.objective());
List<KeyResult> keyResults = duplicateObjectiveDto.keyResults().stream().map(keyResultMapper::toKeyResult)
.toList();
ObjectiveDto duplicatedObjectiveDto = objectiveMapper
.toDto(objectiveAuthorizationService.duplicateEntity(id, objective));
.toDto(objectiveAuthorizationService.duplicateEntity(id, objective, keyResults));
return ResponseEntity.status(HttpStatus.CREATED).body(duplicatedObjectiveDto);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ch.puzzle.okr.dto;

import ch.puzzle.okr.dto.keyresult.KeyResultDto;

import java.util.List;

public record DuplicateObjectiveDto(ObjectiveDto objective, List<KeyResultDto> keyResults) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

import ch.puzzle.okr.models.Objective;
import ch.puzzle.okr.models.authorization.AuthorizationUser;
import ch.puzzle.okr.models.keyresult.KeyResult;
import ch.puzzle.okr.service.business.ObjectiveBusinessService;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;

@Service
public class ObjectiveAuthorizationService extends AuthorizationServiceBase<Long, Objective, ObjectiveBusinessService> {
Expand All @@ -13,10 +17,16 @@ public ObjectiveAuthorizationService(ObjectiveBusinessService objectiveBusinessS
super(objectiveBusinessService, authorizationService);
}

public Objective duplicateEntity(Long id, Objective objective) {
public Objective duplicateEntity(Long id, Objective objective, List<KeyResult> keyResults) {
AuthorizationUser authorizationUser = getAuthorizationService().updateOrAddAuthorizationUser();
hasRoleCreateOrUpdate(objective, authorizationUser);
return getBusinessService().duplicateObjective(id, objective, authorizationUser);
return getBusinessService().duplicateObjective(id, objective, authorizationUser, keyResults);
}

public List<KeyResult> getAllKeyResultsByObjective(Long objectiveId) {
AuthorizationUser authorizationUser = getAuthorizationService().updateOrAddAuthorizationUser();
getAuthorizationService().hasRoleReadByObjectiveId(objectiveId, authorizationUser);
return getBusinessService().getAllKeyResultsByObjective(objectiveId);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@

@Service
public class ObjectiveBusinessService implements BusinessServiceInterface<Long, Objective> {
private static final Logger logger = LoggerFactory.getLogger(ObjectiveBusinessService.class);
private final ObjectivePersistenceService objectivePersistenceService;
private final ObjectiveValidationService validator;
private final KeyResultBusinessService keyResultBusinessService;
private final CompletedBusinessService completedBusinessService;

private static final Logger logger = LoggerFactory.getLogger(ObjectiveBusinessService.class);

public ObjectiveBusinessService(@Lazy KeyResultBusinessService keyResultBusinessService,
ObjectiveValidationService validator, ObjectivePersistenceService objectivePersistenceService,
CompletedBusinessService completedBusinessService) {
Expand All @@ -38,6 +37,10 @@ public ObjectiveBusinessService(@Lazy KeyResultBusinessService keyResultBusiness
this.completedBusinessService = completedBusinessService;
}

private static boolean hasQuarterChanged(Objective objective, Objective savedObjective) {
return !Objects.equals(objective.getQuarter(), savedObjective.getQuarter());
}

public Objective getEntityById(Long id) {
validator.validateOnGet(id);
return objectivePersistenceService.findById(id);
Expand All @@ -48,6 +51,11 @@ public List<Objective> getEntitiesByTeamId(Long id) {
return objectivePersistenceService.findObjectiveByTeamId(id);
}

public List<KeyResult> getAllKeyResultsByObjective(Long objectiveId) {
Objective objective = objectivePersistenceService.findById(objectiveId);
return keyResultBusinessService.getAllKeyResultsByObjective(objective.getId());
}

@Transactional
public Objective updateEntity(Long id, Objective objective, AuthorizationUser authorizationUser) {
Objective savedObjective = objectivePersistenceService.findById(id);
Expand Down Expand Up @@ -88,10 +96,6 @@ private boolean hasAlreadyCheckIns(Objective savedObjective) {
.anyMatch(kr -> keyResultBusinessService.hasKeyResultAnyCheckIns(kr.getId()));
}

private static boolean hasQuarterChanged(Objective objective, Objective savedObjective) {
return !Objects.equals(objective.getQuarter(), savedObjective.getQuarter());
}

@Transactional
public Objective createEntity(Objective objective, AuthorizationUser authorizationUser) {
objective.setCreatedBy(authorizationUser.user());
Expand All @@ -110,13 +114,16 @@ public Objective createEntity(Objective objective, AuthorizationUser authorizati
* New Objective with no KeyResults
* @param authorizationUser
* AuthorizationUser
* @param keyResults
* KeyResults to copy
*
* @return New Objective with copied KeyResults form the source Objective
*/
@Transactional
public Objective duplicateObjective(Long id, Objective objective, AuthorizationUser authorizationUser) {
public Objective duplicateObjective(Long id, Objective objective, AuthorizationUser authorizationUser,
List<KeyResult> keyResults) {
Objective duplicatedObjective = createEntity(objective, authorizationUser);
for (KeyResult keyResult : keyResultBusinessService.getAllKeyResultsByObjective(id)) {
for (KeyResult keyResult : keyResults) {
duplicateKeyResult(authorizationUser, keyResult, duplicatedObjective);
}
return duplicatedObjective;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ insert into key_result (id, version, baseline, description, modified_on, stretch
values (10,1, 465, '', '2023-07-25 08:23:02.273028', 60, 'Im Durchschnitt soll die Lautstärke 60dB nicht überschreiten', 1, 5, 1, 'metric', '2023-07-25 08:23:02.273028', 'PERCENT', null, null, null),
(8,1, 213425, '', '2023-07-25 08:19:44.351252', 80, 'High employee satisfaction scores (80%+) throughout the year.', 1, 4, 1, 'metric', '2023-07-25 08:19:44.351252', 'PERCENT', null, null, null),
(7,1, 84, '', '2023-07-25 08:19:13.569300', 4, 'Monthly town halls between our people and leadership teams over the next four months.', 1, 4, 1, 'metric', '2023-07-25 08:19:13.569300', 'PERCENT', null, null, null),
(6,1, 5, '', '2023-07-25 08:18:44.087674', 1, 'New structure that rewards funny guys and innovation before the end of Q1. ', 1, 4, 1, 'metric', '2023-07-25 08:18:44.087674', 'PERCENT', null, null, null),
(6,1, 5, '', '2023-07-25 08:18:44.087674', 1, 'New structure that rewards funny guys and innovation before the end of Q1.', 1, 4, 1, 'metric', '2023-07-25 08:18:44.087674', 'PERCENT', null, null, null),
(15,1, 0, 'asf', '2023-07-25 08:40:49.412684', 1, ' Lorem ipsum dolor sit amet', 1, 9, 1, 'metric', '2023-07-25 08:40:49.412684', 'PERCENT', null, null, null),
(5,1, null, '', '2023-07-25 08:16:24.466383', null, 'Kundenzufriedenheitsumfrage soll mindestens einmal pro 2 Wochen durchgeführt werden. ', 1, 3, 1, 'ordinal', '2023-07-25 08:16:24.466383', 'PERCENT', 'Fisch', 'Hai', 'MEG'),
(12,1, 0, '', '2023-07-25 08:28:45.110759', 80, 'Wir wollen bereits nach Q1 rund 80% des Redesigns vom OKR-Tool abgeschlossen haben. ', 1, 6, 1, 'metric', '2023-07-25 08:28:45.110759', 'PERCENT', null, null, null),
Expand All @@ -123,9 +123,9 @@ values (1,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam
(3,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:44:54.832400', '', '2023-07-24 22:00:00.000000', 1, 1, 7, 5, 'metric', null),
(4,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:45:07.911215', 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 22:00:00.000000', 7, 1, 7, 5, 'metric', null),
(5,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:45:25.583267', 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-24 22:00:00.000000', 3, 1, 6, 5, 'metric', null),
(6,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:45:42.707340', 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-24 22:00:00.000000', 3, 1, 5, 5, 'metric', null),
(7,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:45:57.304875', '', '2023-07-25 22:00:00.000000', 2, 1, 5, 5, 'metric', null),
(8,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:46:21.358930', 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-24 22:00:00.000000', 70, 1, 4, 5, 'metric', null),
(6,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:45:42.707340', 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-24 22:00:00.000000', null, 1, 5, 5, 'ordinal', 'COMMIT'),
(7,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:45:57.304875', '', '2023-07-25 22:00:00.000000', null, 1, 5, 5, 'ordinal', 'COMMIT'),
(8,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:46:21.358930', 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-24 22:00:00.000000', null, 1, 4, 5, 'ordinal', 'COMMIT'),
(9,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:46:39.204525', 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-24 22:00:00.000000', 16, 1, 3, 5, 'metric', null),
(10,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:47:01.649202', 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-24 22:00:00.000000', 10, 1, 14, 5, 'metric', null),
(11,1, 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores ', '2023-07-25 08:47:22.341767', 'Mehr Kuchen', '2023-07-24 22:00:00.000000', 1, 1, 13, 5, 'metric', null),
Expand Down
Loading
Loading