diff --git a/src/main/kotlin/com/mnnit/moticlubs/controller/UserController.kt b/src/main/kotlin/com/mnnit/moticlubs/controller/UserController.kt index be3ae27..7bb3895 100644 --- a/src/main/kotlin/com/mnnit/moticlubs/controller/UserController.kt +++ b/src/main/kotlin/com/mnnit/moticlubs/controller/UserController.kt @@ -8,12 +8,14 @@ import com.mnnit.moticlubs.dto.response.AdminUserDTO import com.mnnit.moticlubs.service.FCMService import com.mnnit.moticlubs.service.UserService import com.mnnit.moticlubs.utils.Constants.BASE_PATH +import com.mnnit.moticlubs.utils.Constants.CAPTCHA_HEADER import com.mnnit.moticlubs.utils.Constants.STAMP_HEADER import com.mnnit.moticlubs.utils.Constants.USER_ID_CLAIM import com.mnnit.moticlubs.utils.Constants.USER_ROUTE import com.mnnit.moticlubs.utils.ResponseStamp import com.mnnit.moticlubs.utils.ResponseStamp.invalidateStamp import com.mnnit.moticlubs.utils.ServiceLogger +import com.mnnit.moticlubs.utils.UnauthorizedException import com.mnnit.moticlubs.utils.apiWrapper import com.mnnit.moticlubs.utils.invalidateStamp import com.mnnit.moticlubs.utils.validateRequestBody @@ -23,6 +25,7 @@ import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.tags.Tag import org.springframework.http.ResponseEntity import org.springframework.http.server.reactive.ServerHttpRequest +import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping @@ -138,4 +141,31 @@ class UserController( fcmService.updateFcm(FCM(it, dto.token)) } .wrapError() + + @DeleteMapping + @Operation( + summary = "Delete your own account", + description = "This API will delete your account and any actions (that includes posts, " + + "replies and as club admin) permanently. You need to enter your college G-Suite ID email in the captcha.", + ) + fun deleteUser(@RequestHeader(CAPTCHA_HEADER) email: String): Mono> = pathAuthorization + .userAuthorization() + .flatMap { uid -> userService.getUserByUid(uid).map { Pair(uid, it) } } + .flatMap { (uid, user) -> + if (user.email == email) { + LOGGER.info("deleteUser: DELETE ACCOUNT [$uid]") + userService.deleteUser(uid) + } else { + Mono.error(UnauthorizedException("Please enter your email in the captcha")) + } + } + .invalidateStamp { + ResponseStamp.ADMIN.invalidateStamp() + ResponseStamp.MEMBER.invalidateStamp() + ResponseStamp.POST.invalidateStamp() + ResponseStamp.REPLY.invalidateStamp() + ResponseStamp.CHANNEL.invalidateStamp() + ResponseStamp.USER + } + .wrapError() } diff --git a/src/main/kotlin/com/mnnit/moticlubs/service/UserService.kt b/src/main/kotlin/com/mnnit/moticlubs/service/UserService.kt index 6728a12..1603106 100755 --- a/src/main/kotlin/com/mnnit/moticlubs/service/UserService.kt +++ b/src/main/kotlin/com/mnnit/moticlubs/service/UserService.kt @@ -60,4 +60,10 @@ class UserService( @CacheEvict(cacheNames = ["user", "admins", "all_users", "members"], allEntries = true) fun updateContact(uid: Long, contact: String): Mono = userRepository.updateContact(uid, contact) + + @CacheEvict( + cacheNames = ["user", "admins", "all_users", "members", "post", "replies", "all_channels"], + allEntries = true, + ) + fun deleteUser(uid: Long) = userRepository.deleteById(uid) } diff --git a/src/main/kotlin/com/mnnit/moticlubs/utils/Constants.kt b/src/main/kotlin/com/mnnit/moticlubs/utils/Constants.kt index 2e311d4..956bc4b 100644 --- a/src/main/kotlin/com/mnnit/moticlubs/utils/Constants.kt +++ b/src/main/kotlin/com/mnnit/moticlubs/utils/Constants.kt @@ -2,6 +2,7 @@ package com.mnnit.moticlubs.utils object Constants { const val STAMP_HEADER = "X-Stamp-Value" + const val CAPTCHA_HEADER = "X-Captcha-Email" const val BASE_PATH = "api/v1" diff --git a/src/main/kotlin/com/mnnit/moticlubs/utils/Utils.kt b/src/main/kotlin/com/mnnit/moticlubs/utils/Utils.kt index 2a779f1..b6b7b4f 100644 --- a/src/main/kotlin/com/mnnit/moticlubs/utils/Utils.kt +++ b/src/main/kotlin/com/mnnit/moticlubs/utils/Utils.kt @@ -57,6 +57,17 @@ fun Mono.invalidateStamp( .body(it) } +fun Mono.invalidateStamp( + getStampKey: () -> ResponseStamp.StampKey, +): Mono> = then( + Mono.fromCallable { + val updatedStamp = getStampKey().invalidateStamp() + ResponseEntity.ok() + .header(Constants.STAMP_HEADER, updatedStamp.toString()) + .body(null) + }, +) + /** * Supposed to be called after any function of [com.mnnit.moticlubs.web.security.PathAuthorization] */