Skip to content

Commit be1899c

Browse files
committed
feat(group): add support for report group (limit: 5)
1 parent 5f21c72 commit be1899c

5 files changed

Lines changed: 193 additions & 1 deletion

File tree

src/main/kotlin/com/duckbox/controller/GroupController.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,13 @@ class GroupController (
7171
return ResponseEntity.noContent().build()
7272
}
7373

74+
@PostMapping("/api/v1/group/status")
75+
fun reportGroup(@RequestHeader httpHeaders: Map<String, String>, @RequestBody groupId: String): ResponseEntity<Unit> {
76+
val userEmail: String = jwtTokenProvider.getUserPK(jwtTokenProvider.getTokenFromHeader(httpHeaders)!!)
77+
groupService.reportGroup(userEmail, groupId)
78+
return ResponseEntity.noContent().build()
79+
}
80+
7481
@GetMapping("/api/v1/groups/items")
7582
fun findGroupVoteAndSurveyOfUser(@RequestHeader httpHeaders: Map<String, String>): ResponseEntity<List<OverallDetailDto>> {
7683
val userEmail: String = jwtTokenProvider.getUserPK(jwtTokenProvider.getTokenFromHeader(httpHeaders)!!)

src/main/kotlin/com/duckbox/domain/group/GroupEntity.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class GroupEntity (
1515
var description: String,
1616
var profile: ObjectId? = null, // image
1717
var header: ObjectId? = null, // image
18+
var reported: MutableList<String>, // did list who reported this group (limit: 5)
1819
) {
1920
fun toGroupDetailDto(_profile: ByteArray?, _header: ByteArray?): GroupDetailDto {
2021
return GroupDetailDto(

src/main/kotlin/com/duckbox/service/GroupService.kt

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,8 @@ class GroupService (
150150
status = GroupStatus.PENDING,
151151
description = registerDto.description,
152152
profile = profileImageId,
153-
header = headerImageId
153+
header = headerImageId,
154+
reported = mutableListOf()
154155
)
155156
).id
156157

@@ -272,6 +273,32 @@ class GroupService (
272273
userBoxRepository.save(userBox)
273274
}
274275

276+
fun reportGroup(userEmail: String, groupId: String) {
277+
val groupObjectId = ObjectId(groupId)
278+
279+
// check group is valid
280+
lateinit var groupEntity: GroupEntity
281+
runCatching {
282+
groupRepository.findById(groupObjectId).get()
283+
}.onSuccess {
284+
groupEntity = it
285+
}.onFailure {
286+
throw NotFoundException("Invalid GroupId: [${groupId}]")
287+
}
288+
289+
val userDid: String = userRepository.findByEmail(userEmail).did
290+
if (groupEntity.reported.find { it == userDid } != null) {
291+
throw ConflictException("User [$userEmail] has already reported this group[$groupObjectId].")
292+
}
293+
groupEntity.reported.add(userDid)
294+
295+
if (groupEntity.reported.size >= 5 && groupEntity.status != GroupStatus.REPORTED) {
296+
groupEntity.status = GroupStatus.REPORTED
297+
}
298+
299+
groupRepository.save(groupEntity)
300+
}
301+
275302
fun searchGroup(query: String): ResponseEntity<List<GroupDetailDto>> {
276303
val groupDtoList: MutableList<GroupDetailDto> = mutableListOf()
277304
groupRepository.findByNameContains(query).forEach {

src/test/kotlin/com/duckbox/controller/GroupControllerTest.kt

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.duckbox.dto.group.GroupRegisterDto
1313
import com.duckbox.dto.group.GroupUpdateDto
1414
import com.duckbox.dto.user.LoginRequestDto
1515
import com.duckbox.dto.user.RegisterDto
16+
import com.duckbox.errors.exception.ConflictException
1617
import com.duckbox.errors.exception.ForbiddenException
1718
import com.duckbox.errors.exception.NotFoundException
1819
import com.duckbox.service.GroupService
@@ -541,6 +542,80 @@ class GroupControllerTest {
541542
}
542543
}
543544

545+
@Test
546+
fun is_reportGroup_throws_no_authToken_header() {
547+
// arrange
548+
val httpEntity = HttpEntity(ObjectId().toString(), HttpHeaders())
549+
550+
// act, assert
551+
restTemplate
552+
.exchange("${baseAddress}/api/v1/group/status", HttpMethod.POST, httpEntity, Unit::class.java)
553+
.apply {
554+
Assertions.assertThat(statusCode).isEqualTo(HttpStatus.FORBIDDEN)
555+
}
556+
}
557+
558+
@Test
559+
fun is_reportGroup_works_well() {
560+
// arrange
561+
val token: String = registerAndLogin()
562+
registerMockUser2()
563+
val httpHeaders = HttpHeaders().apply {
564+
this["Authorization"] = "Bearer $token"
565+
}
566+
val mockDto: GroupRegisterDto = mockGroupRegisterDto.copy(leader = userRepository.findByEmail(mockUserEmail2).did)
567+
val groupId: String = groupService.registerGroup(mockUserEmail2, mockDto).body!! // mockUser 2
568+
val httpEntity = HttpEntity(groupId, httpHeaders)
569+
570+
// act, assert
571+
restTemplate
572+
.exchange("${baseAddress}/api/v1/group/status", HttpMethod.POST, httpEntity, Unit::class.java)
573+
.apply {
574+
Assertions.assertThat(statusCode).isEqualTo(HttpStatus.NO_CONTENT)
575+
}
576+
}
577+
578+
@Test
579+
fun is_reportGroup_throws_on_invalid_groupId() {
580+
// arrange
581+
val token: String = registerAndLogin()
582+
registerMockUser2()
583+
val httpHeaders = HttpHeaders().apply {
584+
this["Authorization"] = "Bearer $token"
585+
}
586+
val httpEntity = HttpEntity(ObjectId().toString(), httpHeaders)
587+
588+
// act, assert
589+
restTemplate
590+
.exchange("${baseAddress}/api/v1/group/status", HttpMethod.POST, httpEntity, NotFoundException::class.java)
591+
.apply {
592+
Assertions.assertThat(statusCode).isEqualTo(HttpStatus.NOT_FOUND)
593+
}
594+
}
595+
596+
@Test
597+
fun is_reportGroup_throws_on_already_reported() {
598+
// arrange
599+
val token: String = registerAndLogin()
600+
registerMockUser2()
601+
val httpHeaders = HttpHeaders().apply {
602+
this["Authorization"] = "Bearer $token"
603+
}
604+
val mockDto: GroupRegisterDto = mockGroupRegisterDto.copy(leader = userRepository.findByEmail(mockUserEmail2).did)
605+
val groupId: String = groupService.registerGroup(mockUserEmail2, mockDto).body!! // mockUser 2
606+
val httpEntity = HttpEntity(groupId, httpHeaders)
607+
608+
// act
609+
groupService.reportGroup(mockUserEmail, groupId)
610+
611+
// act, assert
612+
restTemplate
613+
.exchange("${baseAddress}/api/v1/group/status", HttpMethod.POST, httpEntity, ConflictException::class.java)
614+
.apply {
615+
Assertions.assertThat(statusCode).isEqualTo(HttpStatus.CONFLICT)
616+
}
617+
}
618+
544619
@Test
545620
fun is_searchGroup_works_no_headers_token() {
546621
// act, assert

src/test/kotlin/com/duckbox/service/GroupServiceTest.kt

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,88 @@ class GroupServiceTest {
530530
}
531531
}
532532

533+
@Test
534+
fun is_reportGroup_works_well() {
535+
// arrange
536+
registerMockUser()
537+
registerMockUser2()
538+
val mockDto: GroupRegisterDto = mockGroupRegisterDto.copy(leader = userRepository.findByEmail(mockUserEmail).did)
539+
val groupId: String = groupService.registerGroup(mockUserEmail, mockDto).body!!
540+
541+
// act
542+
groupService.reportGroup(mockUserEmail2, groupId)
543+
544+
// assert
545+
assertThat(groupRepository.findById(ObjectId(groupId)).get().reported.size).isEqualTo(1)
546+
}
547+
548+
@Test
549+
fun is_reportGroup_works_well_to_limit() {
550+
// arrange
551+
registerMockUser()
552+
val mockDto: GroupRegisterDto = mockGroupRegisterDto.copy(leader = userRepository.findByEmail(mockUserEmail).did)
553+
val groupId: String = groupService.registerGroup(mockUserEmail, mockDto).body!!
554+
555+
val emailList: List<String> = listOf("1@com", "2@com", "3@com", "4@com", "5@com")
556+
val reportedList: MutableList<String> = mutableListOf()
557+
reportedList.add(userService.register(MockDto.mockRegisterDto.copy(email = emailList[0], nickname = "1")).body!!)
558+
reportedList.add(userService.register(MockDto.mockRegisterDto.copy(email = emailList[1], nickname = "2")).body!!)
559+
reportedList.add(userService.register(MockDto.mockRegisterDto.copy(email = emailList[2], nickname = "3")).body!!)
560+
reportedList.add(userService.register(MockDto.mockRegisterDto.copy(email = emailList[3], nickname = "4")).body!!)
561+
reportedList.add(userService.register(MockDto.mockRegisterDto.copy(email = emailList[4], nickname = "5")).body!!)
562+
563+
// act: report to limit(5)
564+
emailList.forEach {
565+
groupService.reportGroup(it, groupId)
566+
}
567+
568+
// assert
569+
groupRepository.findById(ObjectId(groupId)).get().apply {
570+
assertThat(status).isEqualTo(GroupStatus.REPORTED)
571+
assertThat(reported.size).isEqualTo(reportedList.size)
572+
assertThat(reported).isEqualTo(reportedList)
573+
}
574+
}
575+
576+
@Test
577+
fun is_reportGroup_throws_on_invalid_groupId() {
578+
// arrange
579+
registerMockUser()
580+
val invalidGroupId: String = ObjectId().toString()
581+
582+
// act & assert
583+
runCatching {
584+
groupService.reportGroup(mockUserEmail, invalidGroupId)
585+
}.onSuccess {
586+
fail("This should be failed.")
587+
}.onFailure {
588+
assertThat(it is NotFoundException).isEqualTo(true)
589+
assertThat(it.message).isEqualTo("Invalid GroupId: [${invalidGroupId}]")
590+
}
591+
}
592+
593+
@Test
594+
fun is_reportGroup_throws_on_already_reported() {
595+
// arrange
596+
registerMockUser()
597+
registerMockUser2()
598+
val mockDto: GroupRegisterDto = mockGroupRegisterDto.copy(leader = userRepository.findByEmail(mockUserEmail).did)
599+
val groupId: String = groupService.registerGroup(mockUserEmail, mockDto).body!!
600+
601+
// act
602+
groupService.reportGroup(mockUserEmail2, groupId)
603+
604+
// act & assert
605+
runCatching {
606+
groupService.reportGroup(mockUserEmail2, groupId)
607+
}.onSuccess {
608+
fail("This should be failed.")
609+
}.onFailure {
610+
assertThat(it is ConflictException).isEqualTo(true)
611+
assertThat(it.message).isEqualTo("User [$mockUserEmail2] has already reported this group[$groupId].")
612+
}
613+
}
614+
533615
@Test
534616
fun is_searchGroup_works_well() {
535617
// arrange

0 commit comments

Comments
 (0)