Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Original file line number Diff line number Diff line change
@@ -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<Void> adminPasswordUpdate(
@RequestHeader("X-Admin-Id") Long adminId,
@Valid @RequestBody AdminPwUpdateRequest request) {
adminService.updateAdminPassword(adminId, request);
return ResponseEntity.ok().build();
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -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) {}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
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 = "example@gmail.com") String username,
@Schema(description = "κ΄€λ¦¬μž 이름", example = "μ •μ„ μš°") String name,
@Schema(description = "κ΄€λ¦¬μž μ—°λ½μ²˜", example = "010-1234-5678") String contact) {
public static AdminInfoResponse of(Admin admin) {
return new AdminInfoResponse(
admin.getId(), admin.getUsername(), admin.getName(), admin.getContact());
}
}
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -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);
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
118 changes: 118 additions & 0 deletions src/test/java/com/doubleo/adminservice/service/AdminServiceTest.java
Original file line number Diff line number Diff line change
@@ -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 name = "name";
private final String contact = "contact";

private Admin admin;

@BeforeEach
void setUp() {
admin = Admin.createAdmin(username, "encoded", name, contact);
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.name()).isEqualTo(admin.getName());
assertThat(response.contact()).isEqualTo(admin.getContact());
}
}

@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());
}
}
}