diff --git a/src/main/java/com/doubleo/adminservice/domain/admin/controller/.gitkeep b/src/main/java/com/doubleo/adminservice/domain/admin/controller/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/doubleo/adminservice/domain/admin/controller/AdminController.java b/src/main/java/com/doubleo/adminservice/domain/admin/controller/AdminController.java new file mode 100644 index 0000000..19d37b0 --- /dev/null +++ b/src/main/java/com/doubleo/adminservice/domain/admin/controller/AdminController.java @@ -0,0 +1,34 @@ +package com.doubleo.adminservice.domain.admin.controller; + +import com.doubleo.adminservice.domain.admin.dto.request.AdminPwUpdateRequest; +import com.doubleo.adminservice.domain.admin.dto.response.AdminInfoResponse; +import com.doubleo.adminservice.domain.admin.service.AdminService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@Tag(name = "1-1. Admin API", description = "관리자 API") +@RestController +@RequiredArgsConstructor +@RequestMapping("/admins") +public class AdminController { + private final AdminService adminService; + + @Operation(summary = "관리자 본인 정보 조회", description = "관리자 본인 정보를 조회합니다.") + @GetMapping("/me") + public AdminInfoResponse adminGet(@RequestHeader("X-Admin-Id") Long adminId) { + return adminService.getAdminInfo(adminId); + } + + @Operation(summary = "관리자 비밀번호 업데이트", description = "관리자 비밀번호를 업데이트합니다.") + @PatchMapping("/me/password") + public ResponseEntity adminPasswordUpdate( + @RequestHeader("X-Admin-Id") Long adminId, + @Valid @RequestBody AdminPwUpdateRequest request) { + adminService.updateAdminPassword(adminId, request); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/com/doubleo/adminservice/domain/admin/domain/Admin.java b/src/main/java/com/doubleo/adminservice/domain/admin/domain/Admin.java index 8721aaa..5c0f2be 100644 --- a/src/main/java/com/doubleo/adminservice/domain/admin/domain/Admin.java +++ b/src/main/java/com/doubleo/adminservice/domain/admin/domain/Admin.java @@ -23,26 +23,27 @@ public class Admin extends BaseTimeEntity { @Column(name = "admin_password", nullable = false, length = 100) private String password; - @Column(name = "admin_name", nullable = false) - private String name; + @Column(name = "admin_affiliation", nullable = false) + private String affiliation; - @Column(name = "admin_contact", nullable = false) - private String contact; + @Column(name = "admin_affiliation_id", nullable = false) + private String affiliationId; @Builder(access = AccessLevel.PRIVATE) - private Admin(String username, String password, String name, String contact) { + private Admin(String username, String password, String affiliation, String affiliationId) { this.username = username; this.password = password; - this.name = name; - this.contact = contact; + this.affiliation = affiliation; + this.affiliationId = affiliationId; } - public static Admin createAdmin(String username, String password, String name, String contact) { + public static Admin createAdmin( + String username, String password, String affiliation, String affiliationId) { return Admin.builder() .username(username) .password(password) - .name(name) - .contact(contact) + .affiliation(affiliation) + .affiliationId(affiliationId) .build(); } diff --git a/src/main/java/com/doubleo/adminservice/domain/admin/dto/request/.gitkeep b/src/main/java/com/doubleo/adminservice/domain/admin/dto/request/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/doubleo/adminservice/domain/admin/dto/request/AdminPwUpdateRequest.java b/src/main/java/com/doubleo/adminservice/domain/admin/dto/request/AdminPwUpdateRequest.java new file mode 100644 index 0000000..d51a217 --- /dev/null +++ b/src/main/java/com/doubleo/adminservice/domain/admin/dto/request/AdminPwUpdateRequest.java @@ -0,0 +1,12 @@ +package com.doubleo.adminservice.domain.admin.dto.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; + +public record AdminPwUpdateRequest( + @Schema(description = "관리자 기존 패스워드", example = "pw12345") + @NotBlank(message = "기존 비밀번호는 필수입니다.") + String passwordOriginal, + @Schema(description = "관리자 신규 패스워드", example = "pw67890") + @NotBlank(message = "신규 비밀번호는 필수입니다.") + String passwordNew) {} diff --git a/src/main/java/com/doubleo/adminservice/domain/admin/dto/response/.gitkeep b/src/main/java/com/doubleo/adminservice/domain/admin/dto/response/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/doubleo/adminservice/domain/admin/dto/response/AdminInfoResponse.java b/src/main/java/com/doubleo/adminservice/domain/admin/dto/response/AdminInfoResponse.java new file mode 100644 index 0000000..043f0c3 --- /dev/null +++ b/src/main/java/com/doubleo/adminservice/domain/admin/dto/response/AdminInfoResponse.java @@ -0,0 +1,18 @@ +package com.doubleo.adminservice.domain.admin.dto.response; + +import com.doubleo.adminservice.domain.admin.domain.Admin; +import io.swagger.v3.oas.annotations.media.Schema; + +public record AdminInfoResponse( + @Schema(description = "관리자 ID", example = "1") Long adminId, + @Schema(description = "관리자 username", example = "admin1") String username, + @Schema(description = "관리자 소속 병원", example = "서울아산병원") String affiliation, + @Schema(description = "관리자 소속 병원 구분 ID", example = "TSEO09AS") String affiliationId) { + public static AdminInfoResponse of(Admin admin) { + return new AdminInfoResponse( + admin.getId(), + admin.getUsername(), + admin.getAffiliation(), + admin.getAffiliationId()); + } +} diff --git a/src/main/java/com/doubleo/adminservice/domain/admin/repository/.gitkeep b/src/main/java/com/doubleo/adminservice/domain/admin/repository/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/doubleo/adminservice/domain/admin/service/.gitkeep b/src/main/java/com/doubleo/adminservice/domain/admin/service/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/doubleo/adminservice/domain/admin/service/AdminService.java b/src/main/java/com/doubleo/adminservice/domain/admin/service/AdminService.java new file mode 100644 index 0000000..67c9162 --- /dev/null +++ b/src/main/java/com/doubleo/adminservice/domain/admin/service/AdminService.java @@ -0,0 +1,11 @@ +package com.doubleo.adminservice.domain.admin.service; + +import com.doubleo.adminservice.domain.admin.dto.request.AdminPwUpdateRequest; +import com.doubleo.adminservice.domain.admin.dto.response.AdminInfoResponse; + +public interface AdminService { + + AdminInfoResponse getAdminInfo(Long adminId); + + void updateAdminPassword(Long adminId, AdminPwUpdateRequest request); +} diff --git a/src/main/java/com/doubleo/adminservice/domain/admin/service/AdminServiceImpl.java b/src/main/java/com/doubleo/adminservice/domain/admin/service/AdminServiceImpl.java new file mode 100644 index 0000000..45dd8dd --- /dev/null +++ b/src/main/java/com/doubleo/adminservice/domain/admin/service/AdminServiceImpl.java @@ -0,0 +1,53 @@ +package com.doubleo.adminservice.domain.admin.service; + +import com.doubleo.adminservice.domain.admin.domain.Admin; +import com.doubleo.adminservice.domain.admin.dto.request.AdminPwUpdateRequest; +import com.doubleo.adminservice.domain.admin.dto.response.AdminInfoResponse; +import com.doubleo.adminservice.domain.admin.repository.AdminRepository; +import com.doubleo.adminservice.global.exception.CommonException; +import com.doubleo.adminservice.global.exception.errorcode.AdminErrorCode; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.stereotype.Service; + +@Service +@Transactional +@RequiredArgsConstructor +public class AdminServiceImpl implements AdminService { + + private final AdminRepository adminRepository; + private final BCryptPasswordEncoder passwordEncoder; + + @Override + public AdminInfoResponse getAdminInfo(Long adminId) { + Admin admin = findAdmin(adminId); + return AdminInfoResponse.of(admin); + } + + public void updateAdminPassword(Long adminId, AdminPwUpdateRequest request) { + Admin admin = findAdmin(adminId); + validateAdminPassword(request.passwordOriginal(), admin.getPassword()); + isPasswordNew(request.passwordNew(), admin.getPassword()); + admin.updateAdminPassword(passwordEncoder.encode(request.passwordNew())); + } + + // util + private Admin findAdmin(Long adminId) { + return adminRepository + .findById(adminId) + .orElseThrow(() -> new CommonException(AdminErrorCode.ADMIN_NOT_FOUND)); + } + + private void validateAdminPassword(String raw, String encoded) { + if (!passwordEncoder.matches(raw, encoded)) { + throw new CommonException(AdminErrorCode.INVALID_PASSWORD); + } + } + + private void isPasswordNew(String raw, String encoded) { + if (passwordEncoder.matches(raw, encoded)) { + throw new CommonException(AdminErrorCode.DUPLICATED_PASSWORD); + } + } +} diff --git a/src/main/java/com/doubleo/adminservice/domain/auth/controller/AuthController.java b/src/main/java/com/doubleo/adminservice/domain/auth/controller/AuthController.java index a8e7d67..769533a 100644 --- a/src/main/java/com/doubleo/adminservice/domain/auth/controller/AuthController.java +++ b/src/main/java/com/doubleo/adminservice/domain/auth/controller/AuthController.java @@ -20,7 +20,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.util.WebUtils; -@Tag(name = "1-2. Auth API", description = "회원 로그인/로그아웃/Refresh Token 관련 API") +@Tag(name = "1-2. Auth API", description = "관리자 로그인/로그아웃/Refresh Token 관련 API") @RestController @RequiredArgsConstructor @RequestMapping("/auth") @@ -30,7 +30,7 @@ public class AuthController { private final CookieUtil cookieUtil; private final JwtTokenService jwtTokenService; - @Operation(summary = "회원 로그인", description = "회원 로그인을 처리합니다.") + @Operation(summary = "관리자 로그인", description = "관리자 로그인을 처리합니다.") @PostMapping("/login") public ResponseEntity adminLogin(@RequestBody LoginRequest request) { LoginResponse response = authService.loginAdmin(request); @@ -40,7 +40,7 @@ public ResponseEntity adminLogin(@RequestBody LoginRequest reques return ResponseEntity.ok().headers(headers).body(response); } - @Operation(summary = "회원 로그아웃", description = "회원 로그아웃을 처리합니다.") + @Operation(summary = "관리자 로그아웃", description = "관리자 로그아웃을 처리합니다.") @PostMapping("/logout") public ResponseEntity adminLogout( @RequestHeader(HttpHeaders.AUTHORIZATION) String authorizationHeader, diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 0000000..f6caab1 --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1,78 @@ +-- 서울권 (14개) +INSERT INTO admin (admin_username, admin_password, admin_affiliation, admin_affiliation_id) VALUES + +('admin1', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '강북삼성병원', 'TSEO01KS'), +('admin2', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '건국대학교병원', 'TSEO02KK'), +('admin3', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '경희대학교병원', 'TSEO03KH'), +('admin4', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '고려대 구로병원', 'TSEO04KU'), +('admin5', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '삼성서울병원', 'TSEO05SS'), +('admin6', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '서울대학교병원', 'TSEO06SN'), +('admin7', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '연세대 신촌세브란스', 'TSEO07YS'), +('admin8', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '이화여대 목동병원', 'TSEO08EW'), +('admin9', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '서울아산병원', 'TSEO09AS'), +('admin10', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '중앙대학교병원', 'TSEO10CU'), +('admin11', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '고려대 안암병원', 'TSEO11KA'), +('admin12', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '가톨릭 서울성모', 'TSEO12CS'), +('admin13', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '연세대 분당세브란스', 'TSEO13YS'), +('admin14', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '한양대학교병원', 'TSEO14HY'); + +-- 경기 서북권 (4개) +INSERT INTO admin (admin_username, admin_password, admin_affiliation, admin_affiliation_id) VALUES +('admin15', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '가톨릭 인천성모병원', 'TGYW01CI'), +('admin16', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '순천향 부천병원', 'TGYW02SC'), +('admin17', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '길병원', 'TGYW03GL'), +('admin18', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '인하대병원', 'TGYW04IH'); + +-- 경기 남부권 (4개) +INSERT INTO admin (admin_username, admin_password, admin_affiliation, admin_affiliation_id) VALUES +('admin19', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '고려대 안산병원', 'TGYS01KA'), +('admin20', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '분당서울대병원', 'TGYS02SU'), +('admin21', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '아주대학교병원', 'TGYS03AJ'), +('admin22', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '한림대 성심병원', 'TGYS04HL'); + +-- 강원권 (2개) +INSERT INTO admin (admin_username, admin_password, admin_affiliation, admin_affiliation_id) VALUES +('admin23', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '강릉아산병원', 'TGWN01GA'), +('admin24', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '세브란스 원주', 'TGWN02YW'); + +-- 충북권 (1개) +INSERT INTO admin (admin_username, admin_password, admin_affiliation, admin_affiliation_id) VALUES + ('admin25', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '충북대학교병원', 'TCBK01CU'); + +-- 충남권 (3개) +INSERT INTO admin (admin_username, admin_password, admin_affiliation, admin_affiliation_id) VALUES +('admin26', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '단국대병원', 'TCNM01DK'), +('admin27', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '순천향 천안병원', 'TCNM02SC'), +('admin28', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '충남대학교병원', 'TCNM03CN'); + +-- 전북권 (2개) +INSERT INTO admin (admin_username, admin_password, admin_affiliation, admin_affiliation_id) VALUES +('admin29', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '원광대학교병원', 'TJBK01WK'), +('admin30', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '전북대학교병원', 'TJBK02JB'); + +-- 전남권 (3개) +INSERT INTO admin (admin_username, admin_password, admin_affiliation, admin_affiliation_id) VALUES +('admin31', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '전남대학교병원', 'TJNM01JN'), +('admin32', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '조선대학교병원', 'TJNM02CS'), +('admin33', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '화순전남대병원', 'TJNM03HS'); + +-- 경북권 (5개) +INSERT INTO admin (admin_username, admin_password, admin_affiliation, admin_affiliation_id) VALUES +('admin34', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '경북대학교병원', 'TGBK01KB'), +('admin35', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '계명대 동산병원', 'TGBK02KM'), +('admin36', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '대구가톨릭대병원', 'TGBK03DC'), +('admin37', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '영남대학교병원', 'TGBK04YN'), +('admin38', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '칠곡경북대병원', 'TGBK05CB'); + +-- 경남 동부권 (5개) +INSERT INTO admin (admin_username, admin_password, admin_affiliation, admin_affiliation_id) VALUES +('admin39', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '동아대학교병원', 'TGNE01DA'), +('admin40', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '부산대학교병원', 'TGNE02PU'), +('admin41', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '양산부산대병원', 'TGNE03YA'), +('admin42', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '부산백병원', 'TGNE04IB'), +('admin43', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '울산대병원', 'TGNE05UI'); + +-- 경남 서부권 (2개) +INSERT INTO admin (admin_username, admin_password, admin_affiliation, admin_affiliation_id) VALUES +('admin44', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '경상대병원', 'TGNW01GS'), +('admin45', '$2a$10$r8KNcU9cEEuNzBPmCCt8EeNH08JXt8krEWCLU9Yko73jWX7jc3Ehe', '성균관대 삼성창원병원','TGNW02SC'); diff --git a/src/test/java/com/doubleo/adminservice/service/AdminServiceTest.java b/src/test/java/com/doubleo/adminservice/service/AdminServiceTest.java new file mode 100644 index 0000000..71d87b0 --- /dev/null +++ b/src/test/java/com/doubleo/adminservice/service/AdminServiceTest.java @@ -0,0 +1,118 @@ +package com.doubleo.adminservice.service; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.mockito.BDDMockito.*; + +import com.doubleo.adminservice.domain.admin.domain.Admin; +import com.doubleo.adminservice.domain.admin.dto.request.AdminPwUpdateRequest; +import com.doubleo.adminservice.domain.admin.dto.response.AdminInfoResponse; +import com.doubleo.adminservice.domain.admin.repository.AdminRepository; +import com.doubleo.adminservice.domain.admin.service.AdminServiceImpl; +import com.doubleo.adminservice.global.exception.CommonException; +import com.doubleo.adminservice.global.exception.errorcode.AdminErrorCode; +import java.util.Optional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.test.util.ReflectionTestUtils; + +@ExtendWith(MockitoExtension.class) +public class AdminServiceTest { + + @InjectMocks private AdminServiceImpl adminService; + + @Mock private AdminRepository adminRepository; + + @Mock private BCryptPasswordEncoder bCryptPasswordEncoder; + + private final String username = "test@test.com"; + private final String password = "password"; + private final String affiliation = "서울아산병원"; + private final String affiliationId = "000413"; + + private Admin admin; + + @BeforeEach + void setUp() { + admin = Admin.createAdmin(username, "encoded", affiliation, affiliationId); + ReflectionTestUtils.setField(admin, "id", 1L); + } + + @Nested + class getAdminInfo { + + @Test + void 관리자정보_조회하면_정상적으로_반환된다() { + // given + given(adminRepository.findById(1L)).willReturn(Optional.of(admin)); + + // when + AdminInfoResponse response = adminService.getAdminInfo(admin.getId()); + + // then + assertThat(response.adminId()).isEqualTo(admin.getId()); + assertThat(response.username()).isEqualTo(admin.getUsername()); + assertThat(response.affiliation()).isEqualTo(admin.getAffiliation()); + assertThat(response.affiliationId()).isEqualTo(admin.getAffiliationId()); + } + } + + @Nested + class updateAdminPassword { + + @Test + void 비밀번호_변경하면_정상적으로_변경된다() { + // given + String newPassword = "newPassword"; + String encodedNewPassword = "encodedNew"; + + given(adminRepository.findById(1L)).willReturn(Optional.of(admin)); + given(bCryptPasswordEncoder.matches(password, "encoded")).willReturn(true); + given(bCryptPasswordEncoder.encode(newPassword)).willReturn(encodedNewPassword); + + // when + adminService.updateAdminPassword(1L, new AdminPwUpdateRequest(password, newPassword)); + + // then + assertThat(admin.getPassword()).isEqualTo(encodedNewPassword); + } + + @Test + void 기존_비밀번호_유효하지_않으면_오류_발생한다() { + // given + given(adminRepository.findById(1L)).willReturn(Optional.of(admin)); + given(bCryptPasswordEncoder.matches("wrongPassword", "encoded")).willReturn(false); + + // when & then + assertThatThrownBy( + () -> + adminService.updateAdminPassword( + 1L, + new AdminPwUpdateRequest( + "wrongPassword", "newPassword"))) + .isInstanceOf(CommonException.class) + .hasMessage(AdminErrorCode.INVALID_PASSWORD.getMessage()); + } + + @Test + void 기존_비밀번호와_신규_비밀번호가_동일하면_오류_발생한다() { + // given + given(adminRepository.findById(1L)).willReturn(Optional.of(admin)); + given(bCryptPasswordEncoder.matches(password, "encoded")).willReturn(true); + + // when & then + assertThatThrownBy( + () -> + adminService.updateAdminPassword( + 1L, new AdminPwUpdateRequest(password, password))) + .isInstanceOf(CommonException.class) + .hasMessage(AdminErrorCode.DUPLICATED_PASSWORD.getMessage()); + } + } +} diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml index 03eac81..4b6a707 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -5,7 +5,10 @@ spring: datasource: url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=MYSQL - + jpa: + hibernate: + ddl-auto: create-drop + defer-datasource-initialization: true data: redis: host: localhost