Skip to content

Commit

Permalink
Merge pull request #172 from Team-HMH/feat/#171-add-admin-api
Browse files Browse the repository at this point in the history
feat: admin api 추가
  • Loading branch information
kseysh authored Jul 12, 2024
2 parents 8d432d9 + bbb95e8 commit a489c9a
Show file tree
Hide file tree
Showing 35 changed files with 509 additions and 58 deletions.
24 changes: 24 additions & 0 deletions src/main/java/sopt/org/hmh/domain/admin/controller/AdminApi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package sopt.org.hmh.domain.admin.controller;

import io.swagger.v3.oas.annotations.Operation;
import org.springframework.http.ResponseEntity;
import sopt.org.hmh.domain.admin.dto.request.AdminDailyChallengeRequest;
import sopt.org.hmh.domain.admin.dto.request.AdminLoginRequest;
import sopt.org.hmh.domain.admin.dto.request.AdminUserIdRequest;
import sopt.org.hmh.domain.admin.dto.request.AdminUserInfoRequest;
import sopt.org.hmh.domain.admin.dto.response.AdminTokenResponse;
import sopt.org.hmh.global.common.response.BaseResponse;

public interface AdminApi {
@Operation(summary = "관리자 로그인")
ResponseEntity<BaseResponse<AdminTokenResponse>> orderAdminLogin(AdminLoginRequest request);

@Operation(summary = "관리자 권한으로 유저 즉시 삭제")
ResponseEntity<Void> orderAdminWithdrawImmediately(AdminUserIdRequest request);

@Operation(summary = "관리자 권한으로 유저 정보 변경")
ResponseEntity<Void> orderAdminChangeUserInfo(AdminUserInfoRequest request);

@Operation(summary = "관리자 권한으로 유저 챌린지 정보 변경")
ResponseEntity<Void> orderAdminChangeDailyChallengeInfo(AdminDailyChallengeRequest request);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package sopt.org.hmh.domain.admin.controller;

import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import sopt.org.hmh.domain.admin.dto.request.AdminDailyChallengeRequest;
import sopt.org.hmh.domain.admin.dto.request.AdminLoginRequest;
import sopt.org.hmh.domain.admin.dto.request.AdminUserIdRequest;
import sopt.org.hmh.domain.admin.dto.request.AdminUserInfoRequest;
import sopt.org.hmh.domain.admin.dto.response.AdminTokenResponse;
import sopt.org.hmh.domain.admin.exception.AdminSuccess;
import sopt.org.hmh.domain.admin.service.AdminFacade;
import sopt.org.hmh.global.common.response.BaseResponse;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/admin")
public class AdminController implements AdminApi {

private final AdminFacade adminFacade;

@Override
@PostMapping("/login")
public ResponseEntity<BaseResponse<AdminTokenResponse>> orderAdminLogin(
@RequestBody final AdminLoginRequest request) {
return ResponseEntity
.status(AdminSuccess.ADMIN_LOGIN_SUCCESS.getHttpStatus())
.body(BaseResponse.success(AdminSuccess.ADMIN_LOGIN_SUCCESS,
adminFacade.adminLogin(request.authCode())));
}

@Override
@DeleteMapping("/user")
public ResponseEntity<Void> orderAdminWithdrawImmediately(
@RequestBody @Valid final AdminUserIdRequest request) {
adminFacade.withdrawImmediately(request.userId());
return ResponseEntity
.noContent()
.build();
}

@Override
@PatchMapping("/user")
public ResponseEntity<Void> orderAdminChangeUserInfo(
@RequestBody @Valid final AdminUserInfoRequest request) {
adminFacade.changeUserInfo(request);
return ResponseEntity
.noContent()
.build();
}

@Override
@PatchMapping("/challenge/daily")
public ResponseEntity<Void> orderAdminChangeDailyChallengeInfo(
@RequestBody @Valid final AdminDailyChallengeRequest request) {
adminFacade.changeDailyChallengeInfo(request);
return ResponseEntity
.noContent()
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package sopt.org.hmh.domain.admin.dto.request;

import java.time.LocalDate;
import java.util.List;
import sopt.org.hmh.domain.dailychallenge.domain.Status;

public record AdminDailyChallengeRequest(
Long userId,
LocalDate startDate,
List<Status> statuses
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package sopt.org.hmh.domain.admin.dto.request;

public record AdminLoginRequest(
String authCode
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package sopt.org.hmh.domain.admin.dto.request;

public record AdminUserIdRequest(
Long userId
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package sopt.org.hmh.domain.admin.dto.request;

public record AdminUserInfoRequest(
Long userId,
String name,
Integer point
) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package sopt.org.hmh.domain.admin.dto.response;

public record AdminTokenResponse(
String accessToken
) {
}
31 changes: 31 additions & 0 deletions src/main/java/sopt/org/hmh/domain/admin/exception/AdminError.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package sopt.org.hmh.domain.admin.exception;

import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import sopt.org.hmh.global.common.exception.base.ErrorBase;

@AllArgsConstructor
public enum AdminError implements ErrorBase {

// 401 UNAUTHORIZED
INVALID_ADMIN_AUTH_CODE(HttpStatus.UNAUTHORIZED, "관리자 인증 번호가 일치하지 않습니다."),
;

private final HttpStatus status;
private final String errorMessage;

@Override
public int getHttpStatusCode() {
return this.status.value();
}

@Override
public HttpStatus getHttpStatus() {
return this.status;
}

@Override
public String getErrorMessage() {
return this.errorMessage;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package sopt.org.hmh.domain.admin.exception;

import sopt.org.hmh.global.common.exception.base.ExceptionBase;

public class AdminException extends ExceptionBase {

public AdminException(AdminError errorBase) {
super(errorBase);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package sopt.org.hmh.domain.admin.exception;

import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import sopt.org.hmh.global.common.exception.base.SuccessBase;

@AllArgsConstructor
public enum AdminSuccess implements SuccessBase {

// 200 OK
ADMIN_LOGIN_SUCCESS(HttpStatus.OK, "관리자 로그인에 성공했습니다."),

// 204 NO CONTENT
ADMIN_WITHDRAW_IMMEDIATELY_SUCCESS(HttpStatus.NO_CONTENT, "관리자 권한으로 유저 즉시 삭제에 성공했습니다."),
;

private final HttpStatus status;
private final String successMessage;

@Override
public int getHttpStatusCode() {
return this.status.value();
}

@Override
public HttpStatus getHttpStatus() {
return this.status;
}

@Override
public String getSuccessMessage() {
return this.successMessage;
}
}
81 changes: 81 additions & 0 deletions src/main/java/sopt/org/hmh/domain/admin/service/AdminFacade.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package sopt.org.hmh.domain.admin.service;

import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sopt.org.hmh.domain.admin.dto.request.AdminDailyChallengeRequest;
import sopt.org.hmh.domain.admin.dto.request.AdminUserInfoRequest;
import sopt.org.hmh.domain.admin.dto.response.AdminTokenResponse;
import sopt.org.hmh.domain.admin.exception.AdminError;
import sopt.org.hmh.domain.admin.exception.AdminException;
import sopt.org.hmh.domain.challenge.domain.exception.ChallengeError;
import sopt.org.hmh.domain.challenge.domain.exception.ChallengeException;
import sopt.org.hmh.domain.challenge.service.ChallengeService;
import sopt.org.hmh.domain.dailychallenge.domain.Status;
import sopt.org.hmh.domain.dailychallenge.service.DailyChallengeService;
import sopt.org.hmh.domain.user.domain.User;
import sopt.org.hmh.domain.user.service.UserService;
import sopt.org.hmh.global.auth.jwt.TokenService;

@Service
@RequiredArgsConstructor
public class AdminFacade {

@Value("${jwt.admin-auth-code}")
private String adminAuthCode;

private final UserService userService;
private final TokenService tokenService;
private final ChallengeService challengeService;
private final DailyChallengeService dailyChallengeService;

public AdminTokenResponse adminLogin(String authCode) {
validateAdminAuthCode(authCode);
return new AdminTokenResponse(tokenService.issueAdminToken());
}

private void validateAdminAuthCode(String authCode) {
if (!adminAuthCode.equals(authCode)) {
throw new AdminException(AdminError.INVALID_ADMIN_AUTH_CODE);
}
}

@Transactional
public void withdrawImmediately(Long userId) {
userService.checkIsExistUserId(userId);
challengeService.deleteChallengeRelatedByUserId(userId);
userService.withdrawImmediately(userId);
}

@Transactional
public void changeUserInfo(AdminUserInfoRequest request) {
User user = userService.findByIdOrThrowException(request.userId());
if (Objects.nonNull(request.point())) {
user.changePoint(request.point());
}
if (Objects.nonNull(request.name())) {
user.changeName(request.name());
}
}

@Transactional
public void changeDailyChallengeInfo(AdminDailyChallengeRequest request) {
Long currentChallengeId = userService.getCurrentChallengeIdByUserId(request.userId());
List<Status> statuses = request.statuses();
LocalDate challengeDate = request.startDate();

validateStatusesPeriod(currentChallengeId, statuses);
dailyChallengeService.changeInfoOfDailyChallenges(currentChallengeId, statuses, challengeDate);
}

private void validateStatusesPeriod(Long challengeId, List<Status> statuses) {
Integer challengePeriod = challengeService.getChallengePeriod(challengeId);
if (challengePeriod != statuses.size()) {
throw new ChallengeException(ChallengeError.INVALID_PERIOD_NUMERIC);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private LoginResponse performLogin(String socialAccessToken, SocialPlatform soci
kakaoLoginService.updateUserInfoByKakao(loginUser, socialAccessToken);
}
Long userId = loginUser.getId();
return new LoginResponse(userId, tokenService.issueToken(userId));
return new LoginResponse(userId, tokenService.issueToken(userId.toString()));
}

public SocialAccessTokenResponse getSocialAccessTokenByAuthorizationCode(String code) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ public class ChallengeController implements ChallengeApi {

@PostMapping
@Override
public ResponseEntity<BaseResponse<?>> orderAddChallenge(@UserId final Long userId,
@RequestHeader("OS") final String os,
@RequestBody @Valid final ChallengeRequest request) {
public ResponseEntity<BaseResponse<?>> orderAddChallenge(
@UserId final Long userId,
@RequestHeader("OS") final String os,
@RequestBody @Valid final ChallengeRequest request) {
challengeFacade.addChallenge(userId, request, os);

return ResponseEntity
Expand All @@ -37,8 +38,9 @@ public ResponseEntity<BaseResponse<?>> orderAddChallenge(@UserId final Long user

@GetMapping
@Override
public ResponseEntity<BaseResponse<ChallengeResponse>> orderGetChallenge(@UserId final Long userId,
@RequestHeader("OS") final String os) {
public ResponseEntity<BaseResponse<ChallengeResponse>> orderGetChallenge(
@UserId final Long userId,
@RequestHeader("OS") final String os) {
return ResponseEntity
.status(ChallengeSuccess.GET_CHALLENGE_SUCCESS.getHttpStatus())
.body(BaseResponse.success(ChallengeSuccess.GET_CHALLENGE_SUCCESS,
Expand All @@ -47,8 +49,9 @@ public ResponseEntity<BaseResponse<ChallengeResponse>> orderGetChallenge(@UserId

@GetMapping("/home")
@Override
public ResponseEntity<BaseResponse<DailyChallengeResponse>> orderGetDailyChallenge(@UserId final Long userId,
@RequestHeader("OS") final String os) {
public ResponseEntity<BaseResponse<DailyChallengeResponse>> orderGetDailyChallenge(
@UserId final Long userId,
@RequestHeader("OS") final String os) {
return ResponseEntity
.status(ChallengeSuccess.GET_DAILY_CHALLENGE_SUCCESS.getHttpStatus())
.body(BaseResponse.success(ChallengeSuccess.GET_DAILY_CHALLENGE_SUCCESS,
Expand All @@ -57,9 +60,10 @@ public ResponseEntity<BaseResponse<DailyChallengeResponse>> orderGetDailyChallen

@PostMapping("/app")
@Override
public ResponseEntity<BaseResponse<?>> orderAddApps(@UserId final Long userId,
@RequestHeader("OS") final String os,
@RequestBody @Valid final ChallengeAppArrayRequest requests) {
public ResponseEntity<BaseResponse<?>> orderAddApps(
@UserId final Long userId,
@RequestHeader("OS") final String os,
@RequestBody @Valid final ChallengeAppArrayRequest requests) {
challengeFacade.addAppsToCurrentChallenge(userId, requests.apps(), os);

return ResponseEntity
Expand All @@ -70,9 +74,10 @@ public ResponseEntity<BaseResponse<?>> orderAddApps(@UserId final Long userId,

@DeleteMapping("/app")
@Override
public ResponseEntity<BaseResponse<?>> orderRemoveApp(@UserId final Long userId,
@RequestHeader("OS") final String os,
@RequestBody @Valid final AppRemoveRequest request) {
public ResponseEntity<BaseResponse<?>> orderRemoveApp(
@UserId final Long userId,
@RequestHeader("OS") final String os,
@RequestBody @Valid final AppRemoveRequest request) {
challengeFacade.removeAppFromCurrentChallenge(userId, request.appCode(), os);

return ResponseEntity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ public interface ChallengeRepository extends JpaRepository<Challenge, Long> {
Optional<Challenge> findById(Long id);

void deleteByUserIdIn(List<Long> userId);

void deleteByUserId(Long userId);
}
Loading

0 comments on commit a489c9a

Please sign in to comment.