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 @@ -18,7 +18,8 @@ public record SimpleInfo(
String name,
String description,
String logoUrl,
OrgRole myRole
OrgRole myRole,
boolean isCurrentWorkspace
) {}

//내 조직 정보는 SimpleInfo 를 List 로 반환
Expand Down Expand Up @@ -75,4 +76,8 @@ public record OrgInvitationResponse(
String message,
String email
) {}

public record CurrentWorkspace (
Long orgId
) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,20 @@ public static OrgResponse.OrgDetail toOrgDetail(Organization organization) {
}

public static OrgResponse.SimpleInfo toOrgSimpleInfo(OrgMember orgMember) {
//OrgMember 내부에 존재하는 Role 활용
return toOrgSimpleInfo(orgMember, null);
}

public static OrgResponse.SimpleInfo toOrgSimpleInfo(OrgMember orgMember, Long currentOrgId) {
Organization organization = orgMember.getOrganization();
boolean isCurrentWorkSpace = currentOrgId != null && currentOrgId.equals(organization.getId());

return new OrgResponse.SimpleInfo(organization.getId(),
return new OrgResponse.SimpleInfo(
organization.getId(),
organization.getName(),
organization.getDescription(),
organization.getLogoUrl(),
orgMember.getRole()
orgMember.getRole(),
isCurrentWorkSpace
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ public interface OrgService {

OrgResponse.MyOrganizations getMyOrganizations(Long userId);

OrgResponse.CurrentWorkspace setCurrentWorkspace(Long userId, Long orgId);

OrgResponse.CurrentWorkspace getCurrentWorkspace(Long userId);

OrgResponse.OrgDetail getOrganizationDetail(Long orgId);

OrgResponse.MyOrganizations getSoftDeletedOrgs(Long userId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,46 @@ public OrgResponse.Create createOrganization(Long userId, OrgRequest.Create requ

//로그인한 회원이 속한 조직 모두 조회 메서드
public OrgResponse.MyOrganizations getMyOrganizations(Long userId) {
User user = userRepository.findById(userId).orElseThrow(() ->
new UserHandler(UserErrorCode.USER_NOT_FOUND));
Long currentOrgId = user.getCurrentOrgId();

//회원 id 로 OrgMember 모두 조회 -> DB 조회에서 OrgStatus.ACTIVE 인 Organization 만 포함하는 OrgMember 만 조회해 온다.
List<OrgMember> orgMembers = orgMemberRepository.findOrgMemberByUserId(userId);

//각각의 OrgMember 에서 SimpleInfo DTO 로 매핑
List<OrgResponse.SimpleInfo> infos = orgMembers.stream()
.map(OrgConverter::toOrgSimpleInfo)
.map( m -> OrgConverter.toOrgSimpleInfo(m, currentOrgId))
.toList();

//마지막 반환 DTO 로 변환
return OrgConverter.toMyOrganizations(infos);
}

@Override
public OrgResponse.CurrentWorkspace setCurrentWorkspace(Long userId, Long orgId) {
User user = userRepository.findById(userId).orElseThrow(() ->
new UserHandler(UserErrorCode.USER_NOT_FOUND));

orgMemberRepository.findByUserIdAndOrgId(userId, orgId).orElseThrow(() ->
new OrgHandler(OrgErrorCode.ORG_MEMBER_NOT_FOUND));

user.setCurrentOrgId(orgId);

return new OrgResponse.CurrentWorkspace(orgId);
}

@Override
public OrgResponse.CurrentWorkspace getCurrentWorkspace(Long userId) {
User user = userRepository.findById(userId).orElseThrow(() ->
new UserHandler(UserErrorCode.USER_NOT_FOUND));

Long currentOrgId = user.getCurrentOrgId();

// 현재 설정한 워크스페이스가 없다면 null 반환
return new OrgResponse.CurrentWorkspace(currentOrgId);
}

//하나의 조직에 대한 세부 사항(ID, 이름, 설명, logoUrl, createdAt)
public OrgResponse.OrgDetail getOrganizationDetail(Long orgId) {
//해당 조직 id 로 Organization 조회
Expand Down Expand Up @@ -224,6 +252,13 @@ public void removeOrganization(Long userId, Long orgId) {
// 해당 조직에 가입된 모든 회원들의 가입 정보 삭제
List<OrgMember> orgMembers = orgMemberRepository.findOrgMemberByOrg(organization);

// 현재 워크스페이스가 삭제되는 조직인 멤버들의 currentOrgId를 null로 초기화
for (OrgMember member : orgMembers) {
if (Objects.equals(member.getUser().getCurrentOrgId(), orgId)) {
member.getUser().setCurrentOrgId(null);
}
}
Comment thread
jinnieusLab marked this conversation as resolved.

orgMemberRepository.deleteAll(orgMembers);

// 조직 실제 삭제
Expand Down Expand Up @@ -251,6 +286,14 @@ public void removeOrganizationSoft(Long userId, Long orgId) {
throw new OrgHandler(OrgErrorCode.ORG_FORBIDDEN);
}

// 현재 워크스페이스가 삭제되는 조직인 멤버들의 currentOrgId를 null로 초기화
List<OrgMember> orgMembers = orgMemberRepository.findOrgMemberByOrg(organization);
for (OrgMember member : orgMembers) {
if (Objects.equals(member.getUser().getCurrentOrgId(), orgId)) {
member.getUser().setCurrentOrgId(null);
}
}

// 조직 status 만 DELETED 로 변경 후 종료
organization.softDelete();
}
Expand Down Expand Up @@ -283,6 +326,11 @@ public void removeMemberFromOrg(Long userId, Long orgId, Long memberId) {
throw new OrgHandler(OrgErrorCode.ORG_CANNOT_KICK_ADMIN);
}

// 추방되는 멤버의 현재 워크스페이스가 해당 조직이라면 null로 초기화
if (Objects.equals(targetMember.getUser().getCurrentOrgId(), orgId)) {
targetMember.getUser().setCurrentOrgId(null);
}

// 5. 중간 테이블에서 해당 멤버 삭제
orgMemberRepository.delete(targetMember);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public interface OrgMemberRepository extends JpaRepository<OrgMember, Long> {
@Query(value = "select om from OrgMember om join fetch om.organization o where om.user.id = :userId and o.status = 'DELETED' and om.organization.ownerUserId = :userId")
List<OrgMember> findOrgMemberByUserIdSoftDeleted(@Param("userId") Long userId);

//특정 Organization 에 속한 OrgMember 모두 추출하는 메서드
@Query("select om from OrgMember om where om.organization = :organization")
//특정 Organization 에 속한 OrgMember 모두 추출하는 메서드 (N+1 방지, fetch join)
@Query("select om from OrgMember om join fetch om.user where om.organization = :organization")
List<OrgMember> findOrgMemberByOrg(@Param(value = "organization") Organization organization);

// 조직 멤버 조회 (무한 스크롤 - Slice 반환)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,29 @@ public ResponseEntity<DataResponse<OrgResponse.MyOrganizations>> getMyOrganizati
);
}

@PostMapping("/{orgId}/workspace")
public ResponseEntity<DataResponse<OrgResponse.CurrentWorkspace>> setCurrentWorkspace(
@AuthenticationPrincipal(expression = "userId") Long userId,
@PathVariable Long orgId)
{
OrgResponse.CurrentWorkspace response = orgService.setCurrentWorkspace(userId, orgId);

return ResponseEntity.ok(
DataResponse.from(response)
);
}

@GetMapping("/my/workspace")
public ResponseEntity<DataResponse<OrgResponse.CurrentWorkspace>> getCurrentWorkspace(
@AuthenticationPrincipal(expression = "userId") Long userId)
{
OrgResponse.CurrentWorkspace response = orgService.getCurrentWorkspace(userId);

return ResponseEntity.ok(
DataResponse.from(response)
);
}

@GetMapping("/{orgId}")
public ResponseEntity<DataResponse<OrgResponse.OrgDetail>> getOrganizationDetail(@PathVariable Long orgId)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,46 @@ public interface OrgControllerDocs {
@ApiResponse(responseCode = "200", description = "성공"),
@ApiResponse(responseCode = "400_1", description = "조직 이름 중복")
})
public ResponseEntity<DataResponse<OrgResponse.Create>> createOrganization(
ResponseEntity<DataResponse<OrgResponse.Create>> createOrganization(
@AuthenticationPrincipal(expression = "userId") Long userId,
@RequestPart(value = "request") @Valid OrgRequest.Create request,
@RequestPart(value = "image", required = false) MultipartFile image
);

@Operation(
summary = "내가 속한 조직 전체 조회 API",
description = "로그인한 회원이 속한 조직들의 DB id, 이름, 설명, 로고URL, 내 역할(ADMIN/MEMBER) 반환"
description = "로그인한 회원이 속한 조직들의 DB id, 이름, 설명, 로고URL, 내 역할(ADMIN/MEMBER), 조직이 현재 내 워크스페이스인지 여부를 반환"
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "성공"),
@ApiResponse(responseCode = "401_3", description = "토큰 없이 접근 시 실패")
})
public ResponseEntity<DataResponse<OrgResponse.MyOrganizations>> getMyOrganizations(
ResponseEntity<DataResponse<OrgResponse.MyOrganizations>> getMyOrganizations(
@AuthenticationPrincipal(expression = "userId") Long userId);

@Operation(
summary = "현재 워크스페이스 설정 API",
description = "현재 워크스페이스로 설정할 조직의 id를 받아 유저의 현재 워크스페이스로 설정"
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "성공"),
@ApiResponse(responseCode = "401_3", description = "토큰 없이 접근 시 실패"),
@ApiResponse(responseCode = "404_2", description = "해당 조직의 멤버가 아닌 경우")
})
ResponseEntity<DataResponse<OrgResponse.CurrentWorkspace>> setCurrentWorkspace(
@AuthenticationPrincipal(expression = "userId") Long userId,
@PathVariable Long orgId);

@Operation(
summary = "현재 워크스페이스 조회 API",
description = "유저의 현재 워크스페이스를 조회"
)
@ApiResponses({
@ApiResponse(responseCode = "200", description = "성공"),
@ApiResponse(responseCode = "401_3", description = "토큰 없이 접근 시 실패"),
@ApiResponse(responseCode = "404_3", description = "현재 워크스페이스 미설정")
})
ResponseEntity<DataResponse<OrgResponse.CurrentWorkspace>> getCurrentWorkspace(
@AuthenticationPrincipal(expression = "userId") Long userId);

@Operation(
Expand All @@ -51,7 +76,7 @@ public ResponseEntity<DataResponse<OrgResponse.MyOrganizations>> getMyOrganizati
@ApiResponse(responseCode = "404_1", description = "해당 id 값 조직 존재 X"),
@ApiResponse(responseCode = "410_1", description = "해당 조직은 삭제되었습니다 (Soft Delete)")
})
public ResponseEntity<DataResponse<OrgResponse.OrgDetail>> getOrganizationDetail(@PathVariable Long orgId);
ResponseEntity<DataResponse<OrgResponse.OrgDetail>> getOrganizationDetail(@PathVariable Long orgId);

@Operation(
summary = "회원이 만든 조직 중 Soft Deleted 된 조직 목록 조회",
Expand All @@ -61,7 +86,7 @@ public ResponseEntity<DataResponse<OrgResponse.MyOrganizations>> getMyOrganizati
@ApiResponse(responseCode = "200", description = "성공"),
@ApiResponse(responseCode = "404_1", description = "회원 존재 X")
})
public ResponseEntity<DataResponse<OrgResponse.MyOrganizations>> getSoftDeletedOrganizations(
ResponseEntity<DataResponse<OrgResponse.MyOrganizations>> getSoftDeletedOrganizations(
@AuthenticationPrincipal(expression = "userId") Long userId
);

Expand All @@ -79,7 +104,7 @@ public ResponseEntity<DataResponse<OrgResponse.MyOrganizations>> getSoftDeletedO
@ApiResponse(responseCode = "403_1", description = "허가되지 않은 회원의 요청(조직 생성 회원 X)"),
@ApiResponse(responseCode = "404_1", description = "해당 id 조직 존재 X")
})
public ResponseEntity<DataResponse<OrgResponse.Update>> modifyOrganization(
ResponseEntity<DataResponse<OrgResponse.Update>> modifyOrganization(
@AuthenticationPrincipal(expression = "userId") Long userId,
@PathVariable Long orgId,
@RequestPart(value = "request") @Valid OrgRequest.Update request,
Expand All @@ -96,7 +121,7 @@ public ResponseEntity<DataResponse<OrgResponse.Update>> modifyOrganization(
@ApiResponse(responseCode = "404_1", description = "해당 id 조직 존재 X"),
@ApiResponse(responseCode = "409_1", description = "이미 활성화 상태인 조직")
})
public ResponseEntity<DataResponse<OrgResponse.Delete>> restoreOrganization(
ResponseEntity<DataResponse<OrgResponse.Delete>> restoreOrganization(
@AuthenticationPrincipal(expression = "userId") Long userId,
@PathVariable Long orgId
);
Expand All @@ -113,7 +138,7 @@ public ResponseEntity<DataResponse<OrgResponse.Delete>> restoreOrganization(
@ApiResponse(responseCode = "403_1", description = "허가되지 않은 회원의 요청(조직 생성 회원 X)"),
@ApiResponse(responseCode = "404_1", description = "해당 id 조직 존재 X")
})
public ResponseEntity<DataResponse<String>> removeOrganization(
ResponseEntity<DataResponse<String>> removeOrganization(
@AuthenticationPrincipal(expression = "userId") Long userId,
@PathVariable Long orgId,
@RequestParam(defaultValue = "false") boolean isHard
Expand Down Expand Up @@ -155,7 +180,7 @@ ResponseEntity<DataResponse<OrgResponse.OrgMemberCountDTO>> getOrgMembersCount(
@ApiResponse(responseCode = "403", description = "권한이 부족한 경우(요청을 보낸 유저의 권한이 ADMIN이 아닌 경우)"),
@ApiResponse(responseCode = "404", description = "해당 id의 데이터 존재 X")
})
public ResponseEntity<DataResponse<String>> removeMember(
ResponseEntity<DataResponse<String>> removeMember(
@AuthenticationPrincipal(expression = "userId") Long userId,
@PathVariable Long orgId,
@PathVariable Long memberId
Expand Down Expand Up @@ -186,7 +211,7 @@ ResponseEntity<DataResponse<OrgResponse.OrgMemberDTO>> updateOrgMembersRole(
@ApiResponse(responseCode = "404", description = "조직을 찾을 수 없음"),
@ApiResponse(responseCode = "409", description = "이미 조직에 가입된 사용자")
})
public ResponseEntity<DataResponse<OrgResponse.OrgInvitationResponse>> sendOrgInvitation(
ResponseEntity<DataResponse<OrgResponse.OrgInvitationResponse>> sendOrgInvitation(
@AuthenticationPrincipal(expression = "userId") Long userId,
@PathVariable Long orgId,
@RequestBody @Valid OrgRequest.Invite request
Expand All @@ -199,7 +224,7 @@ public ResponseEntity<DataResponse<OrgResponse.OrgInvitationResponse>> sendOrgIn
@ApiResponse(responseCode = "401", description = "로그인 필요"),
@ApiResponse(responseCode = "403", description = "초대된 이메일과 로그인한 사용자가 불일치")
})
public ResponseEntity<DataResponse<OrgResponse.OrgInvitationResponse>> acceptOrgInvitation(
ResponseEntity<DataResponse<OrgResponse.OrgInvitationResponse>> acceptOrgInvitation(
@AuthenticationPrincipal(expression = "userId") Long userId,
@PathVariable String token
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public class User extends BaseEntity {
@ColumnDefault("'ACTIVE'") //기본값 ACTIVE
private UserStatus status; //ACTIVE, SUSPENDED, DELETED

@Column(name = "current_org_id")
private Long currentOrgId;

// 소셜 로그인 시 유저 프로필 최신화
public void updateProfile(String name){
this.name = name;
Expand All @@ -57,4 +60,8 @@ public void modifyInfo(String name, String profileImageUrl, String encodedNewPwd
this.profileImageUrl = profileImageUrl;
this.password = encodedNewPwd;
}

public void setCurrentOrgId(Long currentOrgId) {
this.currentOrgId = currentOrgId;
}
}
Loading