diff --git a/src/main/kotlin/com/seugi/api/domain/chat/application/service/message/MessageServiceImpl.kt b/src/main/kotlin/com/seugi/api/domain/chat/application/service/message/MessageServiceImpl.kt index ad104ad31..6df8a8d03 100644 --- a/src/main/kotlin/com/seugi/api/domain/chat/application/service/message/MessageServiceImpl.kt +++ b/src/main/kotlin/com/seugi/api/domain/chat/application/service/message/MessageServiceImpl.kt @@ -115,7 +115,7 @@ class MessageServiceImpl( chatRoomId = room.id.toString(), timestamp = if (timestamp == DateTimeUtil.localDateTime) LocalDateTime.now() else timestamp ?: LocalDateTime.now() - ).count() + ).count { it.type == Type.MESSAGE || it.type == Type.IMG || it.type == Type.FILE } } @Transactional diff --git a/src/main/kotlin/com/seugi/api/domain/profile/adapter/out/ProfileAdapter.kt b/src/main/kotlin/com/seugi/api/domain/profile/adapter/out/ProfileAdapter.kt index e1e40d7f9..9eab7e19d 100644 --- a/src/main/kotlin/com/seugi/api/domain/profile/adapter/out/ProfileAdapter.kt +++ b/src/main/kotlin/com/seugi/api/domain/profile/adapter/out/ProfileAdapter.kt @@ -1,11 +1,12 @@ package com.seugi.api.domain.profile.adapter.out import com.seugi.api.domain.member.adapter.out.repository.MemberRepository -import com.seugi.api.domain.profile.adapter.out.repository.ProfileRepository import com.seugi.api.domain.member.application.exception.MemberErrorCode import com.seugi.api.domain.profile.adapter.out.mapper.ProfileMapper +import com.seugi.api.domain.profile.adapter.out.repository.ProfileRepository import com.seugi.api.domain.profile.application.exception.ProfileErrorCode import com.seugi.api.domain.profile.application.model.Profile +import com.seugi.api.domain.profile.application.port.out.DeleteProfileUseCase import com.seugi.api.domain.profile.application.port.out.ExistProfilePort import com.seugi.api.domain.profile.application.port.out.LoadProfilePort import com.seugi.api.domain.profile.application.port.out.SaveProfilePort @@ -17,8 +18,8 @@ import org.springframework.stereotype.Component class ProfileAdapter( private val memberRepository: MemberRepository, private val profileRepository: ProfileRepository, - private val profileMapper: ProfileMapper -) : LoadProfilePort, SaveProfilePort, ExistProfilePort { + private val profileMapper: ProfileMapper, +) : LoadProfilePort, SaveProfilePort, ExistProfilePort, DeleteProfileUseCase { override fun loadProfile(memberId: Long, workspaceId: String): Profile { val memberEntity = memberRepository.findByIdOrNull(memberId) @@ -43,4 +44,11 @@ class ProfileAdapter( return profileRepository.existsByMemberAndWorkspaceId(memberEntity, workspaceId) } + override fun deleteProfile(memberId: Long, workspaceId: String) { + val memberEntity = memberRepository.findByIdOrNull(memberId) + ?: throw CustomException(MemberErrorCode.MEMBER_NOT_FOUND) + val profile = profileRepository.findByMemberAndWorkspaceId(memberEntity, workspaceId) + profileRepository.delete(profile!!) + } + } \ No newline at end of file diff --git a/src/main/kotlin/com/seugi/api/domain/profile/application/port/in/ManageProfileUseCase.kt b/src/main/kotlin/com/seugi/api/domain/profile/application/port/in/ManageProfileUseCase.kt index 4b6d8e2ce..45b993562 100644 --- a/src/main/kotlin/com/seugi/api/domain/profile/application/port/in/ManageProfileUseCase.kt +++ b/src/main/kotlin/com/seugi/api/domain/profile/application/port/in/ManageProfileUseCase.kt @@ -6,5 +6,6 @@ import com.seugi.api.domain.workspace.domain.enums.WorkspaceRole interface ManageProfileUseCase { fun manageProfile(memberId: Long, workspaceId: String, permission: WorkspaceRole) + fun deleteProfile(memberId: Long, workspaceId: String) } \ No newline at end of file diff --git a/src/main/kotlin/com/seugi/api/domain/profile/application/port/out/DeleteProfileUseCase.kt b/src/main/kotlin/com/seugi/api/domain/profile/application/port/out/DeleteProfileUseCase.kt new file mode 100644 index 000000000..ae5768e19 --- /dev/null +++ b/src/main/kotlin/com/seugi/api/domain/profile/application/port/out/DeleteProfileUseCase.kt @@ -0,0 +1,5 @@ +package com.seugi.api.domain.profile.application.port.out + +interface DeleteProfileUseCase { + fun deleteProfile(memberId: Long, workspaceId: String) +} \ No newline at end of file diff --git a/src/main/kotlin/com/seugi/api/domain/profile/application/service/ManageProfileService.kt b/src/main/kotlin/com/seugi/api/domain/profile/application/service/ManageProfileService.kt index ea2bcaf79..18b609d2e 100644 --- a/src/main/kotlin/com/seugi/api/domain/profile/application/service/ManageProfileService.kt +++ b/src/main/kotlin/com/seugi/api/domain/profile/application/service/ManageProfileService.kt @@ -6,6 +6,7 @@ import com.seugi.api.domain.profile.application.model.Profile import com.seugi.api.domain.profile.application.model.value.ProfilePermission import com.seugi.api.domain.profile.application.model.value.ProfileWorkspaceId import com.seugi.api.domain.profile.application.port.`in`.ManageProfileUseCase +import com.seugi.api.domain.profile.application.port.out.DeleteProfileUseCase import com.seugi.api.domain.profile.application.port.out.ExistProfilePort import com.seugi.api.domain.profile.application.port.out.LoadProfilePort import com.seugi.api.domain.profile.application.port.out.SaveProfilePort @@ -18,6 +19,7 @@ class ManageProfileService( private val loadMemberPort: LoadMemberPort, private val loaProfilePort: LoadProfilePort, private val saveProfilePort: SaveProfilePort, + private val deleteProfileUseCase: DeleteProfileUseCase, ) : ManageProfileUseCase { override fun manageProfile(memberId: Long, workspaceId: String, permission: WorkspaceRole) { @@ -30,6 +32,10 @@ class ManageProfileService( } } + override fun deleteProfile(memberId: Long, workspaceId: String) { + deleteProfileUseCase.deleteProfile(memberId, workspaceId) + } + private fun updateExistingProfile(memberId: Long, workspaceId: String, permission: WorkspaceRole) { val profile = loaProfilePort.loadProfile(memberId, workspaceId) profile.changeRole(ProfilePermission(permission)) diff --git a/src/main/kotlin/com/seugi/api/domain/workspace/presentation/controller/WorkspaceController.kt b/src/main/kotlin/com/seugi/api/domain/workspace/presentation/controller/WorkspaceController.kt index 5b3f999e8..ed4895822 100644 --- a/src/main/kotlin/com/seugi/api/domain/workspace/presentation/controller/WorkspaceController.kt +++ b/src/main/kotlin/com/seugi/api/domain/workspace/presentation/controller/WorkspaceController.kt @@ -147,4 +147,12 @@ class WorkspaceController( return workspaceService.manageWorkspaceMemberPermission(userId, manageWorkspaceMemberPermissionRequest) } + @PatchMapping("/kick") + fun kickWorkspaceMember( + @GetAuthenticatedId userId: Long, + @RequestBody kickWorkspaceMemberRequest: KickWorkspaceMemberRequest, + ): BaseResponse { + return workspaceService.kickWorkspaceMember(userId, kickWorkspaceMemberRequest) + } + } \ No newline at end of file diff --git a/src/main/kotlin/com/seugi/api/domain/workspace/presentation/dto/request/KickWorkspaceMemberRequest.kt b/src/main/kotlin/com/seugi/api/domain/workspace/presentation/dto/request/KickWorkspaceMemberRequest.kt new file mode 100644 index 000000000..e7d86dc77 --- /dev/null +++ b/src/main/kotlin/com/seugi/api/domain/workspace/presentation/dto/request/KickWorkspaceMemberRequest.kt @@ -0,0 +1,6 @@ +package com.seugi.api.domain.workspace.presentation.dto.request + +data class KickWorkspaceMemberRequest( + val memberList: Set? = null, + val workspaceId: String? = null, +) diff --git a/src/main/kotlin/com/seugi/api/domain/workspace/service/WorkspaceService.kt b/src/main/kotlin/com/seugi/api/domain/workspace/service/WorkspaceService.kt index 801dae026..5d1eb97e9 100644 --- a/src/main/kotlin/com/seugi/api/domain/workspace/service/WorkspaceService.kt +++ b/src/main/kotlin/com/seugi/api/domain/workspace/service/WorkspaceService.kt @@ -35,4 +35,5 @@ interface WorkspaceService { manageWorkspaceMemberPermissionRequest: ManageWorkspaceMemberPermissionRequest, ): BaseResponse + fun kickWorkspaceMember(userId: Long, kickWorkspaceMemberRequest: KickWorkspaceMemberRequest): BaseResponse } \ No newline at end of file diff --git a/src/main/kotlin/com/seugi/api/domain/workspace/service/WorkspaceServiceImpl.kt b/src/main/kotlin/com/seugi/api/domain/workspace/service/WorkspaceServiceImpl.kt index 501a10e10..ed79e9172 100644 --- a/src/main/kotlin/com/seugi/api/domain/workspace/service/WorkspaceServiceImpl.kt +++ b/src/main/kotlin/com/seugi/api/domain/workspace/service/WorkspaceServiceImpl.kt @@ -3,6 +3,7 @@ package com.seugi.api.domain.workspace.service import com.seugi.api.domain.member.adapter.`in`.dto.res.RetrieveMemberResponse import com.seugi.api.domain.member.application.port.out.LoadMemberPort import com.seugi.api.domain.profile.adapter.`in`.response.RetrieveProfileResponse +import com.seugi.api.domain.profile.adapter.out.ProfileAdapter import com.seugi.api.domain.profile.application.port.`in`.ManageProfileUseCase import com.seugi.api.domain.profile.application.port.out.LoadProfilePort import com.seugi.api.domain.workspace.domain.WorkspaceRepository @@ -36,6 +37,7 @@ class WorkspaceServiceImpl( private val loadMemberPort: LoadMemberPort, private val niceSchoolService: NiceSchoolService, private val fcmService: FCMService, + private val profileAdapter: ProfileAdapter, ) : WorkspaceService { private fun genCode(length: Int = 6): String { @@ -477,6 +479,30 @@ class WorkspaceServiceImpl( ) } + @Transactional + override fun kickWorkspaceMember( + userId: Long, + kickWorkspaceMemberRequest: KickWorkspaceMemberRequest, + ): BaseResponse { + val workspaceEntity = findWorkspaceById(kickWorkspaceMemberRequest.workspaceId ?: "") + + if (workspaceEntity.workspaceAdmin != userId && !workspaceEntity.middleAdmin.contains(userId)) throw CustomException( + WorkspaceErrorCode.FORBIDDEN + ) + + kickWorkspaceMemberRequest.memberList?.forEach { + if (!workspaceEntity.middleAdmin.contains(it)) removeUserFromWorkspace(it, workspaceEntity) + profileAdapter.deleteProfile(it, kickWorkspaceMemberRequest.workspaceId ?: "") + } + + + + workspaceRepository.save(workspaceEntity) + return BaseResponse( + message = "맴버 추방 성공" + ) + } + private fun validateUserPermission(userId: Long, workspace: WorkspaceEntity, workspaceRole: WorkspaceRole) { if (workspaceRole == WorkspaceRole.MIDDLE_ADMIN && workspace.workspaceAdmin != userId) { throw CustomException(WorkspaceErrorCode.FORBIDDEN)