Skip to content
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
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ public DmMessageListResponse getMessages(Long userId, Long otherUserId, Long cur
.map(DirectMessageDto::fromDm)
.toList();

list.forEach( dto -> dto.setImageUrl( s3Service.getPresignedGetUrl(dto.getSenderProfileImage()) ) );

// 응답값 생성 후 반환
return DmMessageListResponse.builder()
.messages(list)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
import com.nect.api.domain.home.service.HomeStatisticsQueryService;
import com.nect.api.domain.mypage.dto.MyProjectsResponseDto;
import com.nect.api.domain.mypage.service.MyPageProjectQueryService;
import com.nect.api.domain.mypage.service.UserTeamRoleService;
import com.nect.api.domain.team.project.service.ProjectMemberQueryService;
import com.nect.api.domain.team.project.service.ProjectService;
import com.nect.api.domain.team.project.service.ProjectUserService;
import com.nect.api.global.infra.S3Service;
import com.nect.core.entity.team.Project;
import com.nect.core.entity.team.ProjectInterest;
import com.nect.core.entity.team.enums.MemberMatchable;
import com.nect.core.entity.user.User;
import com.nect.core.entity.user.enums.InterestField;
import com.nect.core.entity.user.enums.Role;
Expand All @@ -37,6 +41,7 @@ public class MainHomeFacade {
private final S3Service s3Service;
private final MyPageProjectQueryService myPageProjectQueryService;
private final ProjectMemberQueryService projectMemberQueryService;
private final ProjectUserService projectUserService;

// 모집 중인 프로젝트
public HomeProjectResponse getRecruitingProjects(Long userId, int count, Role role, InterestField interest){
Expand Down Expand Up @@ -119,15 +124,21 @@ public HomeMembersResponse getMatchableMembers(Long userId, int count, Role role
users = homeMemberQueryService.getAllUsersWithoutUser(userId, safeCount);
}

return buildMemberResponse(users);
List<Long> projectIds = projectUserService.getProjectByLeader(userId).stream()
.map(Project::getId)
.toList();
return buildMemberResponse(projectIds, users);
}

// 홈화면 추천 넥터
public HomeMembersResponse getRecommendedMembers(Long userId, int count) {
int safeCount = safeCount(count);
List<User> users = homeMemberQueryService.getAllUsersWithoutUser(userId, safeCount);

List<HomeMemberItem> items = new ArrayList<>(responsesFromMembers(users));
List<Long> projectIds = projectUserService.getProjectByLeader(userId).stream()
.map(Project::getId)
.toList();
List<HomeMemberItem> items = new ArrayList<>(responsesFromMembersWithMatchable(projectIds, users, false));
Collections.shuffle(items);

return HomeMembersResponse.of(items);
Expand Down Expand Up @@ -183,28 +194,33 @@ private List<HomeProjectItem> responsesFromProjects(List<Project> projects) {
}

// List<User> users -> List<HomeMemberItem>
private List<HomeMemberItem> responsesFromMembers(List<User> users) {
private List<HomeMemberItem> responsesFromMembersWithMatchable(List<Long> projectIds, List<User> users, boolean filterMatchableOnly) {
Map<Long, List<String>> partsByUserId = homeMemberQueryService.partsByUsers(users);

return users.stream()
.map(user -> {
List<String> parts = partsByUserId.getOrDefault(user.getUserId(), List.of());

MemberMatchable matchable = homeMemberQueryService.getMemberMatchable(projectIds, user.getUserId());
if (filterMatchableOnly && matchable != MemberMatchable.MATCHABLE) {
return null;
}
return HomeMemberItem.of(
user.getUserId(),
s3Service.getPresignedGetUrl(user.getProfileImageName()),
user.getName(),
user.getRole() != null ? user.getRole().name() : null,
user.getBio(),
user.getCoreCompetencies(),
user.getUserStatus() != null ? user.getUserStatus().name() : null,
matchable.getDescription(),
false,
parts
);
})
.filter(item -> item != null)
.toList();
}


private HomeProjectResponse buildProjectResponse(List<Project> projects) {
if (projects.isEmpty()) {
return HomeProjectResponse.of(List.of());
Expand All @@ -213,8 +229,8 @@ private HomeProjectResponse buildProjectResponse(List<Project> projects) {
return HomeProjectResponse.of(responsesFromProjects(projects));
}

private HomeMembersResponse buildMemberResponse(List<User> users) {
return HomeMembersResponse.of(responsesFromMembers(users));
private HomeMembersResponse buildMemberResponse(List<Long> projectIds, List<User> users) {
return HomeMembersResponse.of(responsesFromMembersWithMatchable(projectIds, users, true));
}

private int safeCount(int count) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@
import com.nect.api.domain.home.dto.HomeHeaderResponse;
import com.nect.api.domain.user.exception.UserNotFoundException;
import com.nect.api.global.infra.S3Service;
import com.nect.core.entity.team.enums.MemberMatchable;
import com.nect.core.entity.team.enums.ProjectMemberStatus;
import com.nect.core.entity.user.User;
import com.nect.core.entity.user.UserRole;
import com.nect.core.entity.user.UserTeamRole;
import com.nect.core.entity.user.enums.InterestField;
import com.nect.core.entity.user.enums.Role;
import com.nect.core.entity.user.enums.RoleField;
import com.nect.core.repository.user.ProjectUserRepositoryComplete;
import com.nect.core.repository.user.UserTeamRoleRepository;
import com.nect.core.repository.team.ProjectUserRepository;
import com.nect.core.repository.user.UserInterestRepository;
import com.nect.core.repository.user.UserRepository;
import com.nect.core.repository.user.UserRoleRepository;
Expand All @@ -29,6 +35,9 @@ public class HomeMemberQueryService {
private final UserRepository userRepository;
private final UserRoleRepository userRoleRepository;
private final UserInterestRepository userInterestRepository;
private final ProjectUserRepository projectUserRepository;
private final ProjectUserRepositoryComplete projectUserRepositoryComplete;
private final UserTeamRoleRepository userTeamRoleRepository;
private final S3Service s3Service;

public List<User> getFilteredMembers(Long userId, int count, Role role, InterestField interest) {
Expand Down Expand Up @@ -89,4 +98,98 @@ public HomeHeaderResponse getHeaderProfile(Long userId) {
);
}


// 매칭 가능 판단 후 MemberMatchable 반환
public MemberMatchable getMemberMatchable(List<Long> projectIds, Long targetUserId) {
if (projectIds == null || projectIds.isEmpty()) {
return MemberMatchable.MATCH_COMPLETE;
}

int activeProjectCount = projectUserRepository.findActiveProjectsByUserId(targetUserId).size();
if (activeProjectCount < 2) {
// User targetUser = userRepository.findById(targetUserId)
// .orElseThrow(() -> new UserNotFoundException("유저를 찾을 수 없습니다."));
//
// List<UserRole> userRoles = userRoleRepository.findByUser(targetUser);
// if (userRoles.isEmpty()) {
// return MemberMatchable.MATCH_COMPLETE;
// }
//
// List<UserTeamRole> projectRoles = userTeamRoleRepository.findByProjectIdIn(projectIds);
// Map<Long, List<UserTeamRole>> rolesByProjectId = new HashMap<>();
// for (UserTeamRole role : projectRoles) {
// if (role.isDeleted()) {
// continue;
// }
// Long projectId = role.getProject().getId();
// rolesByProjectId.computeIfAbsent(projectId, k -> new java.util.ArrayList<>()).add(role);
// }
//
// var activeMembers = projectUserRepositoryComplete.findByProjectIdInAndMemberStatus(projectIds, ProjectMemberStatus.ACTIVE);
// Map<Long, Map<String, Integer>> activeCountsByProjectId = new HashMap<>();
// for (var member : activeMembers) {
// Long projectId = member.getProject().getId();
// Map<String, Integer> activeCounts = activeCountsByProjectId.computeIfAbsent(projectId, k -> new HashMap<>());
// String key = roleKey(member.getRoleField(), member.getCustomRoleFieldName());
// activeCounts.put(key, activeCounts.getOrDefault(key, 0) + 1);
// }
//
// for (Long projectId : projectIds) {
// List<UserTeamRole> roles = rolesByProjectId.get(projectId);
// if (roles == null || roles.isEmpty()) {
// continue;
// }
//
// Map<String, Integer> activeCounts = activeCountsByProjectId.getOrDefault(projectId, Map.of());
// for (UserTeamRole projectRole : roles) {
// if (projectRole.getRequiredCount() == null || projectRole.getRequiredCount() < 1) {
// continue;
// }
//
// if (!userHasRole(userRoles, projectRole.getRoleField(), projectRole.getCustomRoleFieldName())) {
// continue;
// }
//
// String key = roleKey(projectRole.getRoleField(), projectRole.getCustomRoleFieldName());
// int currentCount = activeCounts.getOrDefault(key, 0);
// if (currentCount < projectRole.getRequiredCount()) {
// return MemberMatchable.MATCHABLE;
// }
// }
// }
return MemberMatchable.MATCHABLE;
}

return MemberMatchable.MATCH_COMPLETE;

}

private static String roleKey(RoleField roleField, String customRoleFieldName) {
String custom = (customRoleFieldName == null) ? "" : customRoleFieldName.trim().toLowerCase();
return roleField.name() + ":" + custom;
}

private static boolean userHasRole(List<UserRole> userRoles, RoleField roleField, String customRoleFieldName) {
if (roleField == RoleField.CUSTOM) {
String custom = (customRoleFieldName == null) ? "" : customRoleFieldName.trim().toLowerCase();
for (UserRole userRole : userRoles) {
if (userRole.getRoleField() != RoleField.CUSTOM) {
continue;
}
String userCustom = (userRole.getCustomField() == null) ? "" : userRole.getCustomField().trim().toLowerCase();
if (custom.equals(userCustom)) {
return true;
}
}
return false;
}

for (UserRole userRole : userRoles) {
if (userRole.getRoleField() == roleField) {
return true;
}
}
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ public record PartDto(
String label,

@JsonProperty("required_count")
Integer requiredCount
Integer requiredCount,

@JsonProperty("members")
List<PartUserInfo> members

) {}

public record PartUserInfo(
@JsonProperty("user_id")
Long userId,
@JsonProperty("profile_image")
String profileImage,
@JsonProperty("name")
String name,
@JsonProperty("part")
String part
) {}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,28 @@
import com.nect.api.domain.mypage.exception.UserTeamRoleException;
import com.nect.api.domain.team.project.enums.code.ProjectErrorCode;
import com.nect.api.domain.team.project.exception.ProjectException;
import com.nect.api.domain.team.project.service.ProjectMemberQueryService;
import com.nect.api.domain.team.project.service.ProjectUserService;
import com.nect.api.global.infra.S3Service;
import com.nect.core.entity.team.Project;
import com.nect.core.entity.team.ProjectTeamRole;
import com.nect.core.entity.team.ProjectUser;
import com.nect.core.entity.team.enums.ProjectMemberStatus;
import com.nect.core.entity.team.enums.ProjectMemberType;
import com.nect.core.entity.user.User;
import com.nect.core.entity.user.UserTeamRole;
import com.nect.core.entity.user.enums.RoleField;
import com.nect.core.repository.team.ProjectRepository;
import com.nect.core.repository.team.ProjectUserRepository;
import com.nect.core.repository.user.UserRepository;
import com.nect.core.repository.user.UserTeamRoleRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
Expand All @@ -31,7 +38,10 @@ public class UserTeamRoleQueryService {
private final UserTeamRoleRepository userTeamRoleRepository;
private final ProjectUserRepository projectUserRepository;
private final ProjectRepository projectRepository;

private final UserRepository userRepository;
private final S3Service s3Service;
private final ProjectUserService projectUserService;
private final ProjectMemberQueryService projectMemberQueryService;

// 마이페이지 팀 파트 조회(UserTeamRole 사용), 프로젝트 멤버면 조회 가능
@Transactional(readOnly = true)
Expand All @@ -53,13 +63,36 @@ public UserTeamRolesResDto readMyPageParts(Long projectId, Long requesterUserId)
userTeamRoleRepository.findAllByProject_IdAndDeletedAtIsNullOrderByIdAsc(projectId);

List<UserTeamRolesResDto.PartDto> parts = roles.stream()
.map(r -> new UserTeamRolesResDto.PartDto(
.map(r -> {

List<ProjectUser> projectUsers = projectUserRepository.findByProjectIdAndRoleField(r.getProject().getId(), r.getRoleField());
List<Long> userIds = projectUsers.stream()
.map(ProjectUser::getUserId)
.toList();

List<User> users = userIds.stream()
.map(userRepository::findById) // Optional<User>
.flatMap(Optional::stream) // 존재하는 것만 User로 변환
.toList();

List<UserTeamRolesResDto.PartUserInfo> userInfos = users.stream()
.map(u -> new UserTeamRolesResDto.PartUserInfo(
u.getUserId(),
s3Service.getPresignedGetUrl(u.getProfileImageName()),
u.getNickname(),
projectMemberQueryService.roleFieldInProject(projectId, u.getUserId()).getLabelEn()
)).toList();

return new UserTeamRolesResDto.PartDto(
r.getId(),
r.getRoleField(),
r.getCustomRoleFieldName(),
r.getLabel(),
r.getRequiredCount()
))
r.getRequiredCount(),
userInfos
);

})
.toList();

return new UserTeamRolesResDto(parts);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
import com.nect.api.domain.home.dto.HomeProjectMembersResponse;
import com.nect.api.domain.team.project.dto.ProjectUsersResDto;
import com.nect.api.domain.team.project.enums.code.ProjectErrorCode;
import com.nect.api.domain.team.project.enums.code.ProjectUserErrorCode;
import com.nect.api.domain.team.project.exception.ProjectException;
import com.nect.api.domain.team.project.exception.ProjectUserException;
import com.nect.api.global.infra.S3Service;
import com.nect.core.entity.team.ProjectUser;
import com.nect.core.entity.team.enums.ProjectMemberStatus;
import com.nect.core.entity.user.User;
import com.nect.core.entity.user.enums.RoleField;
Expand Down Expand Up @@ -131,6 +134,13 @@ public HomeProjectMembersResponse homeReadProjectUsers(Long projectId) {
return new HomeProjectMembersResponse(users);
}

// 특정 사람이 특정 프로젝트에서 어떤 역할인지 ( RoleField )
public RoleField roleFieldInProject(Long projectId, Long userId) {
ProjectUser projectUser = projectUserRepository.findByUserIdAndProjectId(userId, projectId)
.orElseThrow(() -> new ProjectUserException(ProjectUserErrorCode.PROJECT_USER_NOT_FOUND));
return projectUser.getRoleField();
}

private void assertActiveProjectMember(Long projectId, Long userId) {
boolean ok = projectUserRepository.existsByProjectIdAndUserIdAndMemberStatus(
projectId, userId, ProjectMemberStatus.ACTIVE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ public class ProjectUserService {
private final ProjectUserRepository projectUserRepository;
private final ProjectService projectService;

// 내가 리더로 속한 프로젝트 조회
public List<Project> getProjectByLeader(Long userId){
List<ProjectUser> projectUser = projectUserRepository.findByUserIdAndMemberType(userId, ProjectMemberType.LEADER);
return projectUser.stream()
.map(ProjectUser::getProject)
.toList();
}

public ProjectUser addProjectUser(Long userId, Project project, RoleField field){
ProjectUser projectUser = ProjectUser.builder()
.project(project)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public List<EnumValueDto> getRoles() {
public RoleFieldsResponseDto getRoleFields(Role role) {
List<EnumValueDto> fields = Arrays.stream(RoleField.values())
.filter(field -> field.getRole() == null || field.getRole().equals(role))
.map(field -> new EnumValueDto(field.name(), field.getLabelEn(), field.getLabelEn()))
.map(field -> new EnumValueDto(field.name(), field.getDescription(), field.getLabelEn()))
.collect(Collectors.toList());

return new RoleFieldsResponseDto(
Expand Down
Loading