Skip to content

feat: 어드민 복덕방 조회,수정,삭제취소 #631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Jun 26, 2024
Original file line number Diff line number Diff line change
@@ -7,10 +7,12 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import in.koreatech.koin.admin.land.dto.AdminLandsRequest;
import in.koreatech.koin.admin.land.dto.AdminLandResponse;
import in.koreatech.koin.admin.land.dto.AdminLandRequest;
import in.koreatech.koin.admin.land.dto.AdminLandsResponse;

import in.koreatech.koin.global.auth.Auth;
@@ -55,7 +57,7 @@ ResponseEntity<AdminLandsResponse> getLands(
@SecurityRequirement(name = "Jwt Authentication")
@PostMapping("/admin/lands")
ResponseEntity<AdminLandsResponse> postLands(
@RequestBody @Valid AdminLandsRequest adminLandsRequest,
@RequestBody @Valid AdminLandRequest adminLandRequest,
@Auth(permit = {ADMIN}) Integer adminId
);

@@ -75,4 +77,52 @@ ResponseEntity<Void> deleteLand(
@Auth(permit = {ADMIN}) Integer adminId
);

@ApiResponses(
value = {
@ApiResponse(responseCode = "200"),
@ApiResponse(responseCode = "401", content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "403", content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true))),
}
)
@Operation(summary = "복덕방 조회")
@SecurityRequirement(name = "Jwt Authentication")
@GetMapping("/admin/lands/{id}")
ResponseEntity<AdminLandResponse> getLand(
@PathVariable("id") Integer id,
@Auth(permit = {ADMIN}) Integer adminId
);

@ApiResponses(
value = {
@ApiResponse(responseCode = "200"),
@ApiResponse(responseCode = "401", content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "403", content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true))),
}
)
@Operation(summary = "복덕방 수정")
@SecurityRequirement(name = "Jwt Authentication")
@PutMapping("/admin/lands/{id}")
ResponseEntity<Void> updateLand(
@PathVariable("id") Integer id,
@RequestBody @Valid AdminLandRequest request,
@Auth(permit = {ADMIN}) Integer adminId
);

@ApiResponses(
value = {
@ApiResponse(responseCode = "200"),
@ApiResponse(responseCode = "401", content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "403", content = @Content(schema = @Schema(hidden = true))),
@ApiResponse(responseCode = "404", content = @Content(schema = @Schema(hidden = true))),
}
)
@Operation(summary = "복덕방 삭제 취소")
@SecurityRequirement(name = "Jwt Authentication")
@PostMapping("/admin/lands/{id}/undelete")
ResponseEntity<Void> undeleteLand(
@PathVariable("id") Integer id,
@Auth(permit = {ADMIN}) Integer adminId
);
}
Original file line number Diff line number Diff line change
@@ -8,11 +8,13 @@
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import in.koreatech.koin.admin.land.dto.AdminLandsRequest;
import in.koreatech.koin.admin.land.dto.AdminLandResponse;
import in.koreatech.koin.admin.land.dto.AdminLandRequest;
import in.koreatech.koin.admin.land.dto.AdminLandsResponse;
import in.koreatech.koin.admin.land.service.AdminLandService;
import in.koreatech.koin.global.auth.Auth;
@@ -37,10 +39,10 @@ public ResponseEntity<AdminLandsResponse> getLands(

@PostMapping("/admin/lands")
public ResponseEntity<AdminLandsResponse> postLands(
@RequestBody @Valid AdminLandsRequest adminLandsRequest,
@RequestBody @Valid AdminLandRequest adminLandRequest,
@Auth(permit = {ADMIN}) Integer adminId
) {
adminLandService.createLands(adminLandsRequest);
adminLandService.createLands(adminLandRequest);
return ResponseEntity.status(HttpStatus.CREATED).build();
}

@@ -53,4 +55,31 @@ public ResponseEntity<Void> deleteLand(
return null;
}

@GetMapping("/admin/lands/{id}")
public ResponseEntity<AdminLandResponse> getLand(
@PathVariable("id") Integer id,
@Auth(permit = {ADMIN}) Integer adminId
) {
return ResponseEntity.ok().body(adminLandService.getLand(id));
}

@PutMapping("/admin/lands/{id}")
public ResponseEntity<Void> updateLand(
@PathVariable("id") Integer id,
@RequestBody @Valid AdminLandRequest request,
@Auth(permit = {ADMIN}) Integer adminId
) {
adminLandService.updateLand(id, request);
return ResponseEntity.ok().build();
}

@PostMapping("/admin/lands/{id}/undelete")
public ResponseEntity<Void> undeleteLand(
@PathVariable("id") Integer id,
@Auth(permit = {ADMIN}) Integer adminId
) {
adminLandService.undeleteLand(id);
return ResponseEntity.ok().build();
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package in.koreatech.koin.admin.land.dto;


import java.util.List;

import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
@@ -17,7 +16,7 @@
import jakarta.validation.constraints.Size;

@JsonNaming(SnakeCaseStrategy.class)
public record AdminLandsRequest(
public record AdminLandRequest(
@Schema(description = "이름 - not null - 최대 255자", example = "금실타운", requiredMode = REQUIRED)
@NotNull(message = "방이름은 필수입니다.")
@Size(max = 255, message = "방이름의 최대 길이는 255자입니다.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C

@NotBlank가 필요해보입니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵~ 고치겠습니다

@@ -29,17 +28,17 @@ public record AdminLandsRequest(
String internalName,

@Schema(description = "크기", example = "9.0")
String size,
double size,

@Schema(description = "종류 - 최대 20자", example = "원룸")
@Size(max = 20, message = "방종류의 최대 길이는 20자입니다.")
String roomType,

@Schema(description = "위도", example = "36.766205")
String latitude,
double latitude,

@Schema(description = "경도", example = "127.284638")
String longitude,
double longitude,

@Schema(description = "전화번호 - 정규식 `^[0-9]{3}-[0-9]{3,4}-[0-9]{4}$` 을 만족해야함", example = "041-111-1111")
@Pattern(regexp = "^[0-9]{3}-[0-9]{3,4}-[0-9]{4}$", message = "전화번호의 형식이 올바르지 않습니다.")
@@ -101,16 +100,37 @@ public record AdminLandsRequest(
boolean optAirConditioner,

@Schema(description = "샤워기 보유 여부 - null일경우 false로 요청됨", example = "true")
boolean optWasher
boolean optWasher,

@Schema(description = "침대 보유 여부", example = "false")
boolean optBed,

@Schema(description = "책상 보유 여부", example = "true")
boolean optDesk,

@Schema(description = "신발장 보유 여부", example = "true")
boolean optShoeCloset,

@Schema(description = "전자 도어락 보유 여부", example = "true")
boolean optElectronicDoorLocks,

@Schema(description = "비데 보유 여부", example = "false")
boolean optBidet,

@Schema(description = "베란다 보유 여부", example = "false")
boolean optVeranda,

@Schema(description = "엘리베이터 보유 여부", example = "true")
boolean optElevator
) {
public Land toLand() {
return Land.builder()
.name(name)
.internalName(internalName)
.size(size)
.size(String.valueOf(size))
.roomType(roomType)
.latitude(latitude)
.longitude(longitude)
.latitude(String.valueOf(latitude))
.longitude(String.valueOf(longitude))
.phone(phone)
.imageUrls(imageUrls)
.address(address)
@@ -129,6 +149,13 @@ public Land toLand() {
.optWaterPurifier(optWaterPurifier)
.optAirConditioner(optAirConditioner)
.optWasher(optWasher)
.optBed(optBed)
.optDesk(optDesk)
.optShoeCloset(optShoeCloset)
.optElectronicDoorLocks(optElectronicDoorLocks)
.optBidet(optBidet)
.optVeranda(optVeranda)
.optElevator(optElevator)
.build();
}
}
124 changes: 120 additions & 4 deletions src/main/java/in/koreatech/koin/admin/land/dto/AdminLandResponse.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package in.koreatech.koin.admin.land.dto;

import static com.fasterxml.jackson.databind.PropertyNamingStrategies.SnakeCaseStrategy;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;

import java.util.List;

import com.fasterxml.jackson.databind.annotation.JsonNaming;

@@ -10,32 +11,147 @@

@JsonNaming(value = SnakeCaseStrategy.class)
public record AdminLandResponse(
@Schema(description = "고유 id", example = "1", requiredMode = REQUIRED)
@Schema(description = "고유 id", example = "1", requiredMode = Schema.RequiredMode.REQUIRED)
Integer id,

@Schema(description = "이름", example = "금실타운", requiredMode = REQUIRED)
@Schema(description = "이름", example = "금실타운", requiredMode = Schema.RequiredMode.REQUIRED)
String name,

@Schema(description = "내부 이름", example = "금실타운", requiredMode = Schema.RequiredMode.REQUIRED)
String internalName,

@Schema(description = "크기", example = "9.0")
double size,

@Schema(description = "종류", example = "원룸")
String roomType,

@Schema(description = "위도", example = "36.766205")
double latitude,

@Schema(description = "경도", example = "127.284638")
double longitude,

@Schema(description = "전화번호", example = "041-111-1111")
String phone,

@Schema(description = "이미지 URL 리스트")
List<String> imageUrls,

@Schema(description = "주소", example = "충청남도 천안시 동남구 병천면")
String address,

@Schema(description = "설명", example = "1년 계약시 20만원 할인")
String description,

@Schema(description = "층수", example = "4")
Integer floor,

@Schema(description = "보증금", example = "30")
String deposit,

@Schema(description = "월세", example = "200만원 (6개월)")
String monthlyFee,

@Schema(description = "전세", example = "3500")
String charterFee,

@Schema(description = "삭제(soft delete) 여부", example = "false", requiredMode = REQUIRED)
@Schema(description = "관리비", example = "21(1인 기준)")
String managementFee,

@Schema(description = "냉장고 보유 여부", example = "true")
boolean optRefrigerator,

@Schema(description = "옷장 보유 여부", example = "true")
boolean optCloset,

@Schema(description = "TV 보유 여부", example = "true")
boolean optTv,

@Schema(description = "전자레인지 보유 여부", example = "true")
boolean optMicrowave,

@Schema(description = "가스레인지 보유 여부", example = "false")
boolean optGasRange,

@Schema(description = "인덕션 보유 여부", example = "true")
boolean optInduction,

@Schema(description = "정수기 보유 여부", example = "true")
boolean optWaterPurifier,

@Schema(description = "에어컨 보유 여부", example = "true")
boolean optAirConditioner,

@Schema(description = "세탁기 보유 여부", example = "true")
boolean optWasher,

@Schema(description = "침대 보유 여부", example = "false")
boolean optBed,

@Schema(description = "책상 보유 여부", example = "true")
boolean optDesk,

@Schema(description = "신발장 보유 여부", example = "true")
boolean optShoeCloset,

@Schema(description = "전자 도어락 보유 여부", example = "true")
boolean optElectronicDoorLocks,

@Schema(description = "비데 보유 여부", example = "false")
boolean optBidet,

@Schema(description = "베란다 보유 여부", example = "false")
boolean optVeranda,

@Schema(description = "엘리베이터 보유 여부", example = "true")
boolean optElevator,

@Schema(description = "삭제(soft delete) 여부", example = "false", requiredMode = Schema.RequiredMode.REQUIRED)
Boolean isDeleted
) {
public static AdminLandResponse from(Land land) {
return new AdminLandResponse(
land.getId(),
land.getName(),
land.getInternalName(),
land.getSize() == null ? null : land.getSize(),
land.getRoomType(),
land.getLatitude() == null ? null : land.getLatitude(),
land.getLongitude() == null ? null : land.getLongitude(),
land.getPhone(),
convertToList(land.getImageUrls()),
land.getAddress(),
land.getDescription(),
land.getFloor(),
land.getDeposit(),
land.getMonthlyFee(),
land.getCharterFee(),
land.getManagementFee(),
land.isOptRefrigerator(),
land.isOptCloset(),
land.isOptTv(),
land.isOptMicrowave(),
land.isOptGasRange(),
land.isOptInduction(),
land.isOptWaterPurifier(),
land.isOptAirConditioner(),
land.isOptWasher(),
land.isOptBed(),
land.isOptDesk(),
land.isOptShoeCloset(),
land.isOptElectronicDoorLocks(),
land.isOptBidet(),
land.isOptVeranda(),
land.isOptElevator(),
land.isDeleted()
);
}

private static List<String> convertToList(String imageUrls) {
if (imageUrls == null || imageUrls.isEmpty()) {
return List.of();
}
return List.of(imageUrls.replace("[", "").replace("]", "").replace("\"", "").split(","));
}
}
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ public record AdminLandsResponse(
Integer currentPage,

@Schema(description = "집 정보 리스트", requiredMode = REQUIRED)
List<AdminLandResponse> lands
List<SimpleLandInformation> lands
) {
public static AdminLandsResponse of(Page<Land> pagedResult, Criteria criteria) {
return new AdminLandsResponse(
@@ -39,8 +39,41 @@ public static AdminLandsResponse of(Page<Land> pagedResult, Criteria criteria) {
criteria.getPage() + 1,
pagedResult.getContent()
.stream()
.map(AdminLandResponse::from)
.map(SimpleLandInformation::from)
.toList()
);
}
}

@JsonNaming(value = SnakeCaseStrategy.class)
private record SimpleLandInformation(
@Schema(description = "고유 id", example = "1", requiredMode = REQUIRED)
Integer id,

@Schema(description = "이름", example = "금실타운", requiredMode = REQUIRED)
String name,

@Schema(description = "종류", example = "원룸")
String roomType,

@Schema(description = "월세", example = "200만원 (6개월)")
String monthlyFee,

@Schema(description = "전세", example = "3500")
String charterFee,

@Schema(description = "삭제(soft delete) 여부", example = "false", requiredMode = REQUIRED)
Boolean isDeleted
) {
public static SimpleLandInformation from(Land land) {
return new SimpleLandInformation(
land.getId(),
land.getName(),
land.getRoomType(),
land.getMonthlyFee(),
land.getCharterFee(),
land.isDeleted()
);
}
}

}
Original file line number Diff line number Diff line change
@@ -6,7 +6,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import in.koreatech.koin.admin.land.dto.AdminLandsRequest;
import in.koreatech.koin.admin.land.dto.AdminLandResponse;
import in.koreatech.koin.admin.land.dto.AdminLandRequest;
import in.koreatech.koin.admin.land.dto.AdminLandsResponse;
import in.koreatech.koin.admin.land.execption.LandNameDuplicationException;
import in.koreatech.koin.admin.land.repository.AdminLandRepository;
@@ -36,11 +37,11 @@ public AdminLandsResponse getLands(Integer page, Integer limit, Boolean isDelete
}

@Transactional
public void createLands(AdminLandsRequest adminLandsRequest) {
if (adminLandRepository.findByName(adminLandsRequest.name()).isPresent()) {
throw LandNameDuplicationException.withDetail("name: " + adminLandsRequest.name());
public void createLands(AdminLandRequest adminLandRequest) {
if (adminLandRepository.findByName(adminLandRequest.name()).isPresent()) {
throw LandNameDuplicationException.withDetail("name: " + adminLandRequest.name());
}
Land land = adminLandsRequest.toLand();
Land land = adminLandRequest.toLand();
adminLandRepository.save(land);
}

@@ -49,4 +50,54 @@ public void deleteLand(Integer id) {
Land land = adminLandRepository.getById(id);
land.delete();
}

public AdminLandResponse getLand(Integer id) {
Land land = adminLandRepository.getById(id);
return AdminLandResponse.from(land);
}

@Transactional
public void updateLand(Integer id, AdminLandRequest request) {
Land land = adminLandRepository.getById(id);
land.update(
request.internalName(),
request.name(),
request.size(),
request.roomType(),
request.latitude(),
request.longitude(),
request.phone(),
request.imageUrls(),
request.address(),
request.description(),
request.floor(),
request.deposit(),
request.monthlyFee(),
request.charterFee(),
request.managementFee(),
request.optRefrigerator(),
request.optCloset(),
request.optTv(),
request.optMicrowave(),
request.optGasRange(),
request.optInduction(),
request.optWaterPurifier(),
request.optAirConditioner(),
request.optWasher(),
request.optBed(),
request.optDesk(),
request.optShoeCloset(),
request.optElectronicDoorLocks(),
request.optBidet(),
request.optVeranda(),
request.optElevator()
);

}

@Transactional
public void undeleteLand(Integer id) {
Land land = adminLandRepository.getById(id);
land.undelete();
}
}
Original file line number Diff line number Diff line change
@@ -158,7 +158,7 @@ public static LandResponse of(Land land, List<String> imageUrls, String permalin
land.getLongitude(),
land.getAddress(),
land.isOptBed(),
land.getSize(),
String.valueOf(land.getSize()),
land.getPhone(),
land.isOptAirConditioner(),
land.getName(),
52 changes: 52 additions & 0 deletions src/main/java/in/koreatech/koin/domain/land/model/Land.java
Original file line number Diff line number Diff line change
@@ -235,6 +235,13 @@ public Double getLongitude() {
return Double.parseDouble(longitude);
}

public Double getSize() {
if (this.size == null) {
return null;
}
return Double.parseDouble(size);
}

private String convertToSting(List<String> imageUrls) {
if (imageUrls == null || imageUrls.isEmpty()) {
return null;
@@ -247,4 +254,49 @@ private String convertToSting(List<String> imageUrls) {
public void delete() {
this.isDeleted = true;
}

public void undelete() {
this.isDeleted = false;
}

public void update(String internalName, String name, double size, String roomType, double latitude,
double longitude,
String phone, List<String> imageUrls, String address, String description, Integer floor,
String deposit, String monthlyFee, String charterFee, String managementFee, boolean optRefrigerator,
boolean optCloset, boolean optTv, boolean optMicrowave, boolean optGasRange, boolean optInduction,
boolean optWaterPurifier, boolean optAirConditioner, boolean optWasher, boolean optBed, boolean optDesk,
boolean optShoeCloset, boolean optElectronicDoorLocks, boolean optBidet, boolean optVeranda,
boolean optElevator) {
this.internalName = internalName;
this.name = name;
this.size = String.valueOf(size);
this.roomType = roomType;
this.latitude = String.valueOf(latitude);
this.longitude = String.valueOf(longitude);
this.phone = phone;
this.imageUrls = convertToSting(imageUrls);
this.address = address;
this.description = description;
this.floor = floor;
this.deposit = deposit;
this.monthlyFee = monthlyFee;
this.charterFee = charterFee;
this.managementFee = managementFee;
this.optRefrigerator = optRefrigerator;
this.optCloset = optCloset;
this.optTv = optTv;
this.optMicrowave = optMicrowave;
this.optGasRange = optGasRange;
this.optInduction = optInduction;
this.optWaterPurifier = optWaterPurifier;
this.optAirConditioner = optAirConditioner;
this.optWasher = optWasher;
this.optBed = optBed;
this.optDesk = optDesk;
this.optShoeCloset = optShoeCloset;
this.optElectronicDoorLocks = optElectronicDoorLocks;
this.optBidet = optBidet;
this.optVeranda = optVeranda;
this.optElevator = optElevator;
}
}
240 changes: 209 additions & 31 deletions src/test/java/in/koreatech/koin/admin/acceptance/AdminLandApiTest.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,23 @@
package in.koreatech.koin.admin.acceptance;

import static in.koreatech.koin.support.JsonAssertions.assertThat;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
import static org.hibernate.validator.internal.util.Contracts.assertNotNull;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertAll;

import java.util.List;
import java.util.Optional;

import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;

import in.koreatech.koin.AcceptanceTest;
import in.koreatech.koin.admin.land.dto.AdminLandsRequest;
import in.koreatech.koin.admin.land.repository.AdminLandRepository;
import in.koreatech.koin.domain.land.model.Land;
import in.koreatech.koin.domain.user.model.User;
import in.koreatech.koin.fixture.LandFixture;
import in.koreatech.koin.fixture.UserFixture;
import in.koreatech.koin.support.JsonAssertions;
import io.restassured.RestAssured;

@SuppressWarnings("NonAsciiCharacters")
@@ -29,6 +26,9 @@ class AdminLandApiTest extends AcceptanceTest {
@Autowired
private AdminLandRepository adminLandRepository;

@Autowired
private LandFixture landFixture;

@Autowired
private UserFixture userFixture;

@@ -78,32 +78,32 @@ void getLands() {
@DisplayName("관리자 권한으로 복덕방을 추가한다.")
void postLands() {
String jsonBody = """
{
"name": "금실타운",
"internal_name": "금실타운",
"size": "9.0",
"room_type": "원룸",
"latitude": "37.555",
"longitude": "126.555",
"phone": "041-111-1111",
"image_urls": ["http://image1.com", "http://image2.com"],
"address": "충청남도 천안시 동남구 병천면",
"description": "1년 계약시 20만원 할인",
"floor": 4,
"deposit": "30",
"monthly_fee": "200만원 (6개월)",
"charter_fee": "3500",
"management_fee": "21(1인 기준)",
"opt_closet": true,
"opt_tv": true,
"opt_microwave": true,
"opt_gas_range": false,
"opt_induction": true,
"opt_water_purifier": true,
"opt_air_conditioner": true,
"opt_washer": true
}
""";
{
"name": "금실타운",
"internal_name": "금실타운",
"size": "9.0",
"room_type": "원룸",
"latitude": "37.555",
"longitude": "126.555",
"phone": "041-111-1111",
"image_urls": ["http://image1.com", "http://image2.com"],
"address": "충청남도 천안시 동남구 병천면",
"description": "1년 계약시 20만원 할인",
"floor": 4,
"deposit": "30",
"monthly_fee": "200만원 (6개월)",
"charter_fee": "3500",
"management_fee": "21(1인 기준)",
"opt_closet": true,
"opt_tv": true,
"opt_microwave": true,
"opt_gas_range": false,
"opt_induction": true,
"opt_water_purifier": true,
"opt_air_conditioner": true,
"opt_washer": true
}
""";

User adminUser = userFixture.코인_운영자();
String token = userFixture.getToken(adminUser);
@@ -167,4 +167,182 @@ void deleteLand() {
softly.assertThat(deletedLand.isDeleted()).isEqualTo(true);
});
}

@Test
@DisplayName("관리자의 권한으로 특정 복덕방 정보를 조회한다.")
void getLand() {
// 복덕방 생성
Land request = Land.builder()
.internalName("금실타운")
.name("금실타운")
.roomType("원룸")
.latitude("37.555")
.longitude("126.555")
.size("9.0")
.monthlyFee("100")
.charterFee("1000")
.address("가전리 123")
.description("테스트용 복덕방")
.build();

Land savedLand = adminLandRepository.save(request);
Comment on lines +174 to +188
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixture를 써도 괜찮지 않을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 생성을 하고 조회하는 방법을 생각했었는데 fixture를 가져오는거도 방법이겠네요~

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

진호는 이제 비즈니스팀인가요?담부터 pr날리면 리뷰어에 등록할게요 ㅋㅋㅋ

Integer landId = savedLand.getId();

User adminUser = userFixture.코인_운영자();
String token = userFixture.getToken(adminUser);

var response = RestAssured
.given()
.header("Authorization", "Bearer " + token)
.when()
.get("/admin/lands/{id}", landId)
.then()
.statusCode(HttpStatus.OK.value())
.extract();

JsonAssertions.assertThat(response.asPrettyString())
.isEqualTo(String.format("""
{
"id": %d,
"name": "금실타운",
"internal_name": "금실타운",
"size": 9.0,
"room_type": "원룸",
"latitude": 37.555,
"longitude": 126.555,
"phone": null,
"image_urls": [],
"address": "가전리 123",
"description": "테스트용 복덕방",
"floor": null,
"deposit": null,
"monthly_fee": "100",
"charter_fee": "1000",
"management_fee": null,
"opt_closet": false,
"opt_tv": false,
"opt_microwave": false,
"opt_gas_range": false,
"opt_induction": false,
"opt_water_purifier": false,
"opt_air_conditioner": false,
"opt_washer": false,
"opt_bed": false,
"opt_bidet": false,
"opt_desk": false,
"opt_electronic_door_locks": false,
"opt_elevator": false,
"opt_refrigerator": false,
"opt_shoe_closet": false,
"opt_veranda": false,
"is_deleted": false
}
""", landId));
}

@Test
@DisplayName("관리자 권한으로 복덕방 정보를 수정한다.")
void updateLand() {
Land land = landFixture.신안빌();
Integer landId = land.getId();

User adminUser = userFixture.코인_운영자();
String token = userFixture.getToken(adminUser);

String jsonBody = """
{
"name": "신안빌 수정",
"internal_name": "신안빌",
"size": "110.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C

스웨거거상에서는 latitude, longitude, size가 number로 들어가고있는데 문제 없을까요?!

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분도 수정을 해야겠네요

"room_type": "투룸",
"latitude": "37.556",
"longitude": "126.556",
"phone": "010-1234-5679",
"image_urls": ["http://newimage1.com", "http://newimage2.com"],
"address": "서울시 강남구 신사동",
"description": "신안빌 수정 설명",
"floor": 5,
"deposit": "50",
"monthly_fee": "150만원",
"charter_fee": "5000",
"management_fee": "150",
"opt_closet": true,
"opt_tv": false,
"opt_microwave": true,
"opt_gas_range": false,
"opt_induction": true,
"opt_water_purifier": false,
"opt_air_conditioner": true,
"opt_washer": true
}
""";

RestAssured
.given()
.header("Authorization", "Bearer " + token)
.contentType("application/json")
.body(jsonBody)
.when()
.put("/admin/lands/{id}", landId)
.then()
.statusCode(HttpStatus.OK.value())
.extract();

Land updatedLand = adminLandRepository.getById(landId);

assertSoftly(softly -> {
softly.assertThat(updatedLand.getName()).isEqualTo("신안빌 수정");
softly.assertThat(updatedLand.getInternalName()).isEqualTo("신안빌");
softly.assertThat(updatedLand.getSize()).isEqualTo(110.0);
softly.assertThat(updatedLand.getRoomType()).isEqualTo("투룸");
softly.assertThat(updatedLand.getLatitude()).isEqualTo(37.556);
softly.assertThat(updatedLand.getLongitude()).isEqualTo(126.556);
softly.assertThat(updatedLand.getPhone()).isEqualTo("010-1234-5679");
softly.assertThat(updatedLand.getImageUrls()).containsAnyOf("http://newimage1.com", "http://newimage2.com");
softly.assertThat(updatedLand.getAddress()).isEqualTo("서울시 강남구 신사동");
softly.assertThat(updatedLand.getDescription()).isEqualTo("신안빌 수정 설명");
softly.assertThat(updatedLand.getFloor()).isEqualTo(5);
softly.assertThat(updatedLand.getDeposit()).isEqualTo("50");
softly.assertThat(updatedLand.getMonthlyFee()).isEqualTo("150만원");
softly.assertThat(updatedLand.getCharterFee()).isEqualTo("5000");
softly.assertThat(updatedLand.getManagementFee()).isEqualTo("150");
softly.assertThat(updatedLand.isOptCloset()).isTrue();
softly.assertThat(updatedLand.isOptTv()).isFalse();
softly.assertThat(updatedLand.isOptMicrowave()).isTrue();
softly.assertThat(updatedLand.isOptGasRange()).isFalse();
softly.assertThat(updatedLand.isOptInduction()).isTrue();
softly.assertThat(updatedLand.isOptWaterPurifier()).isFalse();
softly.assertThat(updatedLand.isOptAirConditioner()).isTrue();
softly.assertThat(updatedLand.isOptWasher()).isTrue();
softly.assertThat(updatedLand.isDeleted()).isEqualTo(false);
});
}

@Test
@DisplayName("관리자 권한으로 복덕방 삭제를 취소한다.")
void undeleteLand() {
Land deletedLand = landFixture.삭제된_복덕방();
Integer landId = deletedLand.getId();

User adminUser = userFixture.코인_운영자();
String token = userFixture.getToken(adminUser);

RestAssured
.given()
.header("Authorization", "Bearer " + token)
.when()
.post("/admin/lands/{id}/undelete", landId)
.then()
.statusCode(HttpStatus.OK.value())
.extract();

Land undeletedLand = adminLandRepository.getById(landId);

SoftAssertions.assertSoftly(softly -> {
softly.assertThat(undeletedLand).isNotNull();
softly.assertThat(undeletedLand.getName()).isEqualTo("삭제된 복덕방");
softly.assertThat(undeletedLand.isDeleted()).isFalse();
});
}

}
20 changes: 20 additions & 0 deletions src/test/java/in/koreatech/koin/fixture/LandFixture.java
Original file line number Diff line number Diff line change
@@ -66,4 +66,24 @@ public LandFixture(LandRepository landRepository) {
.build()
);
}

public Land 삭제된_복덕방() {
List<String> imageUrls = List.of(
"https://example1.test.com/image.jpeg",
"https://example2.test.com/image.jpeg"
);
return landRepository.save(
Land.builder()
.internalName("삭제된 복덕방")
.name("삭제된 복덕방")
.roomType("원룸")
.latitude("37.555")
.longitude("126.555")
.monthlyFee("100")
.charterFee("1000")
.isDeleted(true)
.imageUrls(imageUrls)
.build()
);
}
}