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

DEAR-133 #23

Merged
merged 3 commits into from
Aug 5, 2024
Merged
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
2 changes: 1 addition & 1 deletion database/01_init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ CREATE TABLE sprint_config
end_date DATE NOT NULL,
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
created_by INTEGER NOT NULL,
active BOOLEAN,
status VARCHAR(20) NOT NULL,

PRIMARY KEY (id)
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
package ch.fhnw.deardevbackend.controller;

import ch.fhnw.deardevbackend.dto.ActiveSprintsDTO;
import ch.fhnw.deardevbackend.dto.CreateSprintDTO;
import ch.fhnw.deardevbackend.dto.SprintIdAndTeamIdDTO;
import ch.fhnw.deardevbackend.dto.SprintsAndTeamsDTO;
import ch.fhnw.deardevbackend.entities.SprintConfig;
import ch.fhnw.deardevbackend.entities.User;
import ch.fhnw.deardevbackend.mapper.SprintConfigMapper;
import ch.fhnw.deardevbackend.services.SprintConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.List;

@RestController
Expand All @@ -32,16 +33,24 @@ public ResponseEntity<SprintConfig> getSprintById(@PathVariable Integer sprintId
return ResponseEntity.ok().body(sprintConfig);
}

@PostMapping("/create")
public ResponseEntity<SprintConfig> createSprint(@RequestBody CreateSprintDTO request) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
User user = (User) authentication.getPrincipal();
@GetMapping("/sprints-and-teams")
public ResponseEntity<SprintsAndTeamsDTO> getSprintsAndTeams() {
Integer userId = getCurrentUserFromContext().getId();
SprintsAndTeamsDTO sprintsAndTeams = sprintConfigService.getSprintsAndTeams(userId);
return ResponseEntity.ok().body(sprintsAndTeams);
}

SprintConfig sprintConfig = SprintConfigMapper.INSTANCE.toEntity(request);
sprintConfig.setCreatedBy(user.getId());
sprintConfig.setCreatedAt(LocalDateTime.now());
@GetMapping("/active")
public ResponseEntity<List<ActiveSprintsDTO>> getActiveSprints() {
Integer userId = getCurrentUserFromContext().getId();
List<ActiveSprintsDTO> activeSprints = sprintConfigService.getActiveSprints(userId);
return ResponseEntity.ok().body(activeSprints);
}

SprintConfig createdSprint = sprintConfigService.createSprint(sprintConfig);
@PostMapping("/create")
public ResponseEntity<SprintConfig> createSprint(@RequestBody CreateSprintDTO request) {
Integer userId = getCurrentUserFromContext().getId();
SprintConfig createdSprint = sprintConfigService.createSprint(request, userId);
return ResponseEntity.ok().body(createdSprint);
}

Expand All @@ -50,4 +59,29 @@ public ResponseEntity<SprintConfig> updateSprintConfig(@PathVariable Integer spr
SprintConfig updatedSprint = sprintConfigService.updateSprint(sprintId, request);
return ResponseEntity.ok().body(updatedSprint);
}

@PutMapping("/complete/{sprintId}")
public ResponseEntity<String> completeSprint(@PathVariable Integer sprintId) {
try {
sprintConfigService.completeSprint(sprintId);
return ResponseEntity.ok().body("Sprint completed successfully");
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}

@PostMapping("/start")
public ResponseEntity<String> startSprint(@RequestBody SprintIdAndTeamIdDTO request) {
try {
sprintConfigService.startSprint(request.getTeamId(), request.getSprintId());
return ResponseEntity.ok().body("Sprint started successfully");
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}

private User getCurrentUserFromContext() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return (User) authentication.getPrincipal();
}
}
10 changes: 10 additions & 0 deletions src/main/java/ch/fhnw/deardevbackend/dto/ActiveSprintsDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ch.fhnw.deardevbackend.dto;

import ch.fhnw.deardevbackend.entities.SprintConfig;
import lombok.Data;

@Data
public class ActiveSprintsDTO {
private String teamName;
private SprintConfig sprint;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ch.fhnw.deardevbackend.dto;

import lombok.Data;

@Data
public class SprintIdAndTeamIdDTO {
private Integer teamId;
private Integer sprintId;
}
17 changes: 17 additions & 0 deletions src/main/java/ch/fhnw/deardevbackend/dto/SprintsAndTeamsDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package ch.fhnw.deardevbackend.dto;

import ch.fhnw.deardevbackend.entities.SprintConfig;
import ch.fhnw.deardevbackend.entities.Team;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SprintsAndTeamsDTO {
private List<Team> teams;
private List<SprintConfig> sprints;
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class SprintConfig {
@Column(name = "sprint_goal")
private String sprintGoal;

@ManyToOne(fetch = FetchType.LAZY)
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "team_id", referencedColumnName = "id")
private Team team;

Expand All @@ -42,6 +42,7 @@ public class SprintConfig {
@Column(name = "created_by")
private Integer createdBy;

@Column(name = "active")
private boolean active;
@Enumerated(EnumType.STRING)
@Column(name = "status")
private SprintStatus status;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ch.fhnw.deardevbackend.entities;

public enum SprintStatus {
OPEN,
IN_PROGRESS,
COMPLETED,
DELETED
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,8 @@ public interface SprintConfigMapper {

SprintConfigMapper INSTANCE = Mappers.getMapper(SprintConfigMapper.class);

@Mapping(target = "id", ignore = true)
@Mapping(target = "active", ignore = true)
SprintConfig toEntity(CreateSprintDTO dto);

@Mapping(target = "createdAt", ignore = true)
@Mapping(target = "createdBy", ignore = true)
@Mapping(target = "active", ignore = true)
@Mapping(target = "status", ignore = true)
SprintConfig updateSprintFromDTO(CreateSprintDTO dto, @MappingTarget SprintConfig sprintConfig);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package ch.fhnw.deardevbackend.repositories;

import ch.fhnw.deardevbackend.entities.SprintConfig;
import ch.fhnw.deardevbackend.entities.SprintStatus;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
import java.util.List;

@Repository
public interface SprintConfigRepository extends JpaRepository<SprintConfig, Integer> {

List<SprintConfig> findByTeamIdAndStatus(Integer teamId, SprintStatus status);

List<SprintConfig> findAllByCreatedBy(Integer createdBy);

List<SprintConfig> findByCreatedByAndStatusAndStartDateAfter(Integer createdBy, SprintStatus status, LocalDate startDate);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,28 @@

import ch.fhnw.deardevbackend.entities.Team;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;
import java.util.Optional;

public interface TeamRepository extends JpaRepository<Team, Integer> {

boolean existsByCode(String code);

Optional<Team> findByCode(String code);

@Query("SELECT t from Team t JOIN TeamMember tm ON t.id = tm.teamId WHERE tm.userId = :userId AND t.active = TRUE")
List<Team> findActiveTeamsByUserId(Integer userId);

@Query("""
SELECT t\s
FROM Team t\s
LEFT JOIN SprintConfig sc ON t.currentSprintId = sc.id
JOIN TeamMember tm ON t.id = tm.teamId\s
WHERE tm.userId = :userId\s
AND t.active = TRUE\s
AND (t.currentSprintId IS NULL OR sc.status = 'COMPLETED')
\s""")
List<Team> findActiveTeamsWithNoActiveSprintByUserId(Integer userId);
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
package ch.fhnw.deardevbackend.services;

import ch.fhnw.deardevbackend.controller.exceptions.YappiException;
import ch.fhnw.deardevbackend.dto.ActiveSprintsDTO;
import ch.fhnw.deardevbackend.dto.CreateSprintDTO;
import ch.fhnw.deardevbackend.dto.SprintsAndTeamsDTO;
import ch.fhnw.deardevbackend.entities.SprintConfig;
import ch.fhnw.deardevbackend.entities.SprintStatus;
import ch.fhnw.deardevbackend.entities.Team;
import ch.fhnw.deardevbackend.mapper.SprintConfigMapper;
import ch.fhnw.deardevbackend.repositories.SprintConfigRepository;
import ch.fhnw.deardevbackend.repositories.TeamRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

Expand All @@ -18,6 +26,8 @@ public class SprintConfigService {
@Autowired
private SprintConfigRepository sprintConfigRepository;
@Autowired
private TeamRepository teamRepository;
@Autowired
private SprintConfigMapper sprintConfigMapper;

public List<SprintConfig> getSprintsByCreatedBy(Integer userId) {
Expand All @@ -28,8 +38,42 @@ public SprintConfig getSprintById(Integer sprintId) {
return sprintConfigRepository.findById(sprintId).orElseThrow(() -> new YappiException("Sprint not found with id: " + sprintId));
}

public SprintConfig createSprint(SprintConfig sprintConfig) {
return sprintConfigRepository.save(sprintConfig);
public SprintsAndTeamsDTO getSprintsAndTeams(Integer userId) {
List<Team> teams = teamRepository.findActiveTeamsWithNoActiveSprintByUserId(userId);
LocalDate today = LocalDate.now();
List<SprintConfig> sprints = sprintConfigRepository.findByCreatedByAndStatusAndStartDateAfter(userId, SprintStatus.OPEN, today.minusDays(1));

return new SprintsAndTeamsDTO(teams, sprints);
}

public List<ActiveSprintsDTO> getActiveSprints(Integer userId) {
List<Team> teams = teamRepository.findActiveTeamsByUserId(userId);
List<ActiveSprintsDTO> activeSprints = new ArrayList<>();
for (Team team : teams) {
List<SprintConfig> sprints = sprintConfigRepository.findByTeamIdAndStatus(team.getId(), SprintStatus.IN_PROGRESS);
for (SprintConfig sprint : sprints) {
ActiveSprintsDTO dto = new ActiveSprintsDTO();
dto.setTeamName(team.getName());
dto.setSprint(sprint);
activeSprints.add(dto);
}
}
return activeSprints;
}

public SprintConfig createSprint(CreateSprintDTO dto, Integer userId) {

SprintConfig sprint = SprintConfig.builder()
.sprintName(dto.getSprintName())
.sprintGoal(dto.getSprintGoal())
.startDate(dto.getStartDate())
.endDate(dto.getEndDate())
.createdAt(LocalDateTime.now())
.createdBy(userId)
.status(SprintStatus.OPEN)
.build();

return sprintConfigRepository.save(sprint);
}

@Transactional
Expand All @@ -45,4 +89,22 @@ public SprintConfig updateSprint(Integer id, CreateSprintDTO dto) {
}
}

@Transactional
public void startSprint(Integer teamId, Integer sprintId) {
Team team = teamRepository.findById(teamId).orElseThrow(() -> new YappiException("Team not found with id: " + teamId));
team.setCurrentSprintId(sprintId);
teamRepository.save(team);

SprintConfig sprint = sprintConfigRepository.findById(sprintId).orElseThrow(() -> new YappiException("Sprint not found with id: " + sprintId));
sprint.setStatus(SprintStatus.IN_PROGRESS);
sprint.setTeam(team);
sprintConfigRepository.save(sprint);
}

@Transactional
public void completeSprint(Integer sprintId) {
SprintConfig sprint = sprintConfigRepository.findById(sprintId).orElseThrow(() -> new YappiException("Sprint not found with id: " + sprintId));
sprint.setStatus(SprintStatus.COMPLETED);
sprintConfigRepository.save(sprint);
}
}