Skip to content

Commit

Permalink
DEAR-136: add delete user
Browse files Browse the repository at this point in the history
  • Loading branch information
baurnick committed Aug 8, 2024
1 parent 65e67fe commit fbe3f74
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 11 deletions.
2 changes: 1 addition & 1 deletion database/01_init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ CREATE TABLE team_member
active BOOLEAN DEFAULT TRUE NOT NULL,

CONSTRAINT pk_team_member PRIMARY KEY (id),
CONSTRAINT fk_team_member_user FOREIGN KEY (user_id) REFERENCES users (id),
CONSTRAINT fk_team_member_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
CONSTRAINT fk_team_member_team FOREIGN KEY (team_id) REFERENCES team (id),
CONSTRAINT uq_team_member UNIQUE (user_id, team_id, role)
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package ch.fhnw.deardevbackend.controller;

import ch.fhnw.deardevbackend.dto.TeamWithMembersDTO;
import ch.fhnw.deardevbackend.entities.User;
import ch.fhnw.deardevbackend.services.TeamMemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -17,6 +20,12 @@ public class TeamMemberController {

@GetMapping("/{teamId}")
public TeamWithMembersDTO getTeamMembersByTeamId(@PathVariable Integer teamId) {
return teamMemberService.getTeamMembersByTeamId(teamId);
Integer userId = getCurrentUser().getId();
return teamMemberService.getTeamMembersByTeamId(teamId, userId);
}

private User getCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
return (User) authentication.getPrincipal();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,9 @@ public ResponseEntity<UserAndProviderDTO> getUserByProviderById(@PathVariable In
public void updateUser(@RequestBody UserDTO request) {
userService.updateUser(request.getId(), request.getUsername(), request.getGithubUserName());
}

@DeleteMapping("user/delete/{id}")
public void deleteUser(@PathVariable Integer id) {
userService.deleteUser(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,21 @@

import ch.fhnw.deardevbackend.entities.Account;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Repository
public interface AccountRepository extends JpaRepository<Account, Integer> {
@Query(
value = "select provider from accounts where \"userId\" = :userId",
nativeQuery = true)
String findProviderByUserId(@Param("userId") Integer userId);

@Transactional
@Modifying
@Query(value = "delete from accounts where \"userId\" = :userId", nativeQuery = true)
void deleteByUserId(Integer userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import ch.fhnw.deardevbackend.entities.EmotionSurvey;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

Expand All @@ -18,4 +20,8 @@ public interface EmotionSurveyRepository extends JpaRepository<EmotionSurvey, In
nativeQuery = true)
List<String> findTopTwoTrackedEmotions(Integer userId);

@Transactional
@Modifying
@Query("DELETE FROM EmotionSurvey es WHERE es.userId = :userId")
void deleteByUserId(Integer userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import ch.fhnw.deardevbackend.entities.HappinessSurvey;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
Expand Down Expand Up @@ -43,5 +45,8 @@ List<Object[]> findDailyAveragesByUserIdAndDateRange(@Param("userId") Integer us
@Query("SELECT AVG(h.score) FROM HappinessSurvey h WHERE h.userId = :userId AND DATE(h.submitted) = :date")
Double findAverageScoreByUserIdAndDate(Integer userId, LocalDate date);


@Transactional
@Modifying
@Query("DELETE FROM HappinessSurvey h WHERE h.userId = :userId")
void deleteByUserId(Integer userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ public interface TeamMemberRepository extends JpaRepository<TeamMember, Integer>

@Query("SELECT tm.teamId FROM TeamMember tm WHERE tm.userId = :userId AND tm.active = true")
List<Integer> findTeamIdByUserId(@Param("userId") Integer userId);

List<TeamMember> findByTeamId(Integer teamId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import ch.fhnw.deardevbackend.entities.WorkKindSurvey;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;


@Repository
Expand All @@ -18,6 +20,8 @@ public interface WorkKindSurveyRepository extends JpaRepository<WorkKindSurvey,
"LIMIT 1", nativeQuery = true)
String findMostTrackedWorkType(@Param("userId") Integer userId);

@Query("SELECT COUNT(DISTINCT wk.id) FROM WorkKind wk WHERE wk.teamId = :teamId")
int findDistinctWorkKindCountByTeamId(@Param("teamId") Integer teamId);
@Transactional
@Modifying
@Query("DELETE FROM WorkKindSurvey ws WHERE ws.userId = :userId")
void deleteByUserId(Integer userId);
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package ch.fhnw.deardevbackend.services;

import ch.fhnw.deardevbackend.dto.TeamWithMembersDTO;
import ch.fhnw.deardevbackend.entities.Role;
import ch.fhnw.deardevbackend.entities.Team;
import ch.fhnw.deardevbackend.entities.TeamMemberWithUser;
import ch.fhnw.deardevbackend.mapper.TeamWithMembersMapper;
import ch.fhnw.deardevbackend.repositories.TeamMemberWithUserRepository;
import ch.fhnw.deardevbackend.repositories.TeamRepository;
import ch.fhnw.deardevbackend.util.SecurityUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
Expand All @@ -24,11 +24,12 @@ public class TeamMemberService {
@Autowired
private TeamWithMembersMapper teamWithMembersMapper;

public TeamWithMembersDTO getTeamMembersByTeamId(Integer teamId) {
public TeamWithMembersDTO getTeamMembersByTeamId(Integer teamId, Integer userId) {
List<TeamMemberWithUser> members = teamMemberWithUserRepository.findByTeamId(teamId);
Team team = teamRepository.findById(teamId).orElseThrow(() -> new RuntimeException("Team not found with id: " + teamId));

boolean isAdmin = team.getCreatedBy().equals(SecurityUtil.getCurrentUserId());
boolean isAdmin = members.stream()
.anyMatch(member -> member.getUser().getId().equals(userId) && member.getRole().equals(Role.ADMIN));

return teamWithMembersMapper.toDTO(team, members, isAdmin);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -79,6 +80,7 @@ public Team createTeam(CreateTeamDTO teamDTO) {
.userId(teamDTO.getUserId())
.teamId(savedTeam.getId())
.role(Role.ADMIN)
.joinedAt(LocalDateTime.now())
.active(true)
.build();
teamMemberRepository.save(teamMember);
Expand All @@ -95,6 +97,7 @@ public Team joinTeam(JoinTeamDTO joinTeamDTO) {
.userId(joinTeamDTO.getUserId())
.teamId(team.getId())
.role(Role.MEMBER)
.joinedAt(LocalDateTime.now())
.active(true)
.build();

Expand Down
50 changes: 47 additions & 3 deletions src/main/java/ch/fhnw/deardevbackend/services/UserService.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
package ch.fhnw.deardevbackend.services;

import ch.fhnw.deardevbackend.controller.exceptions.YappiException;
import ch.fhnw.deardevbackend.dto.UserAndProviderDTO;
import ch.fhnw.deardevbackend.dto.UserDTO;
import ch.fhnw.deardevbackend.entities.Role;
import ch.fhnw.deardevbackend.entities.Team;
import ch.fhnw.deardevbackend.entities.TeamMember;
import ch.fhnw.deardevbackend.entities.User;
import ch.fhnw.deardevbackend.mapper.UserMapper;
import ch.fhnw.deardevbackend.mapper.UserProviderMapper;
import ch.fhnw.deardevbackend.repositories.AccountRepository;
import ch.fhnw.deardevbackend.repositories.TeamMemberRepository;
import ch.fhnw.deardevbackend.repositories.UserRepository;
import ch.fhnw.deardevbackend.repositories.*;
import lombok.RequiredArgsConstructor;
import org.springdoc.api.OpenApiResourceNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;

Expand All @@ -28,8 +32,16 @@ public class UserService {
@Autowired
private TeamMemberRepository teamMemberRepository;
@Autowired
private TeamRepository teamRepository;
@Autowired
private UserProviderMapper userProviderMapper;
@Autowired
private EmotionSurveyRepository emotionSurveyRepository;
@Autowired
private HappinessSurveyRepository happinessSurveyRepository;
@Autowired
private WorkKindSurveyRepository workKindSurveyRepository;
@Autowired
private UserMapper userMapper;

public List<User> getAllUsers() {
Expand Down Expand Up @@ -61,6 +73,31 @@ public void updateUser(Integer id, String username, String githubUserName) {
}
}

@Transactional
public void deleteUser(Integer userId) {
emotionSurveyRepository.deleteByUserId(userId);
happinessSurveyRepository.deleteByUserId(userId);
workKindSurveyRepository.deleteByUserId(userId);
List<TeamMember> teamMembers = teamMemberRepository.findByUserId(userId);
for (TeamMember teamMember : teamMembers) {
teamMember.setActive(false);
if (teamMember.getRole().equals(Role.ADMIN)) {
List<TeamMember> currentTeamMembers = teamMemberRepository.findByTeamId(teamMember.getTeamId());
if (currentTeamMembers.size() > 1) {
TeamMember newAdmin = findClosestJoinedMember(teamMember, currentTeamMembers);
newAdmin.setRole(Role.ADMIN);
teamMemberRepository.save(newAdmin);
} else {
Team team = teamRepository.findById(teamMember.getTeamId()).orElseThrow(() -> new YappiException("Team with id " + teamMember.getTeamId() + " not found"));
team.setActive(false);
teamRepository.save(team);
}
}
}

accountRepository.deleteByUserId(userId);
userRepository.deleteById(userId);
}
// used for JWT filter
public Optional<User> findUserByEmail(String email) {
return userRepository.findByEmail(email);
Expand All @@ -70,4 +107,11 @@ public Optional<User> findUserByEmail(String email) {
public Optional<User> findUserById(Integer id) {
return userRepository.findById(id);
}

private TeamMember findClosestJoinedMember(TeamMember currentAdmin, List<TeamMember> currentTeamMembers) {
return currentTeamMembers.stream()
.filter(member -> !member.equals(currentAdmin))
.min(Comparator.comparing(member -> Math.abs(Duration.between(currentAdmin.getJoinedAt(), member.getJoinedAt()).toMillis())))
.orElseThrow(() -> new YappiException("No closest joined member found"));
}
}

0 comments on commit fbe3f74

Please sign in to comment.