Skip to content

Commit

Permalink
Merge pull request #26 from DEPthes/feat/item-category
Browse files Browse the repository at this point in the history
사용자 계정 조회 및 카테고리별 아이템 목록 조회 기능 구현
  • Loading branch information
EunbeenDev authored Aug 12, 2024
2 parents 894e686 + 094c7a2 commit e9904d7
Show file tree
Hide file tree
Showing 14 changed files with 319 additions and 20 deletions.
17 changes: 15 additions & 2 deletions src/main/java/com/noplanb/domain/auth/application/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import com.noplanb.domain.user.domain.User;
import com.noplanb.domain.user.repository.UserRepository;
import com.noplanb.global.config.security.util.JwtTokenUtil;
import com.noplanb.global.payload.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

Expand All @@ -33,7 +35,7 @@ public String verifyIdTokenAndExtractUsername(String idToken, String email) {
return idTokenVerifier.verifyIdToken(idToken, email);
}

public LoginResponse loginWithIdToken(String idToken, String email) {
public ResponseEntity<?> loginWithIdToken(String idToken, String email) {
String username = verifyIdTokenAndExtractUsername(idToken, email);
if (username != null) {
String accessToken = jwtTokenUtil.generateToken(new HashMap<>(), username);
Expand All @@ -59,7 +61,18 @@ public LoginResponse loginWithIdToken(String idToken, String email) {
userRepository.save(user);
}

return new LoginResponse(accessToken, refreshToken);
LoginResponse loginResponse = LoginResponse.builder()
.accessToken(accessToken)
.refreshToken(refreshToken)
.build();

ApiResponse apiResponse = ApiResponse.builder()
.check(true)
.information(loginResponse)
.build();

return ResponseEntity.ok(apiResponse);

} else {
throw new RuntimeException("유효하지 않은 ID 토큰");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ public ResponseEntity<?> idTokenLogin(@RequestBody SigninReq signinReq) {
}

try {
LoginResponse loginResponse = authService.loginWithIdToken(accessToken, email);
Map<String, String> response = new HashMap<>();
response.put("accessToken", loginResponse.getAccessToken());
response.put("refreshToken", loginResponse.getRefreshToken());

ApiResponse apiResponse = ApiResponse.builder()
.check(true)
.information(response)
.build();
return ResponseEntity.ok(apiResponse);
return authService.loginWithIdToken(accessToken, email);
// Map<String, String> response = new HashMap<>();
// response.put("accessToken", loginResponse.getAccessToken());
// response.put("refreshToken", loginResponse.getRefreshToken());
//
// ApiResponse apiResponse = ApiResponse.builder()
// .check(true)
// .information(response)
// .build();
// return ResponseEntity.ok(apiResponse);

} catch (RuntimeException e) {
ErrorCode errorCode = ErrorCode.INVALID_TOKEN;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ public MyCharaterListRes getMyCharacterDetail(UserPrincipal userPrincipal) {
// 캐릭터 상태만을 그대로 반환
public ResponseEntity<?> getMyCharacter(UserPrincipal userPrincipal){
MyCharaterListRes myCharaterListRes = getMyCharacterDetail(userPrincipal);
return ResponseEntity.ok(myCharaterListRes);

ApiResponse apiResponse = ApiResponse.builder()
.check(true)
.information(myCharaterListRes)
.build();
return ResponseEntity.ok(apiResponse);
}

// 캐릭터 상태 + 이름 + 성장 시작일 + 총 경험치 + 달성한 전체 퀘스트 개수 + 성장일 반환
Expand Down Expand Up @@ -85,7 +90,12 @@ public ResponseEntity<?> getMyCharacterInfo(UserPrincipal userPrincipal){
.myCharaterDetailResList(myCharaterListRes.getMyCharaterDetailResList())
.build();

return ResponseEntity.ok(myCharacterInfoRes);
ApiResponse apiResponse = ApiResponse.builder()
.check(true)
.information(myCharacterInfoRes)
.build();

return ResponseEntity.ok(apiResponse);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public ResponseEntity<?> getMyCharacterInfo(@Parameter @CurrentUser UserPrincipa
return characterService.getMyCharacterInfo(userPrincipal);
}

@Operation(summary = "캐릭터와 이름 업데이터 API", description = "마이페이지에서 캐릭터 이름을 변경하는 API입니다.")
@Operation(summary = "캐릭터와 이름 업데이트 API", description = "마이페이지에서 캐릭터 이름을 변경하는 API입니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "캐릭터 이름 업데이트 성공", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = Message.class) ) } ),
@ApiResponse(responseCode = "400", description = "캐릭터 이름 업데이트 실패", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class) ) } ),
Expand Down
94 changes: 94 additions & 0 deletions src/main/java/com/noplanb/domain/item/application/ItemService.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,105 @@
package com.noplanb.domain.item.application;

import com.noplanb.domain.character.domain.Character;
import com.noplanb.domain.character.repository.CharacterRepository;
import com.noplanb.domain.item.dto.response.CategoryItemListRes;
import com.noplanb.domain.item.domain.Item;
import com.noplanb.domain.item.dto.response.CategoryItemRes;
import com.noplanb.domain.item_image.domain.repository.ItemImageRepository;
import com.noplanb.global.config.security.token.UserPrincipal;
import com.noplanb.global.payload.ApiResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import static com.noplanb.domain.item.domain.ItemType.*;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class ItemService {

private final CharacterRepository characterRepository;
private final ItemImageRepository itemImageRepository;


public ResponseEntity<?> getHairItemList(UserPrincipal userPrincipal) {
return getCategoryItemList(userPrincipal, "hair");
}

public ResponseEntity<?> getFaceItemList(UserPrincipal userPrincipal) {
return getCategoryItemList(userPrincipal, "face");
}

public ResponseEntity<?> getFashionItemList(UserPrincipal userPrincipal) {
return getCategoryItemList(userPrincipal, "fashion");
}

public ResponseEntity<?> getBackgroundItemList(UserPrincipal userPrincipal) {
return getCategoryItemList(userPrincipal, "background");
}

public ResponseEntity<?> getCategoryItemList(UserPrincipal userPrincipal, String category) {
Character character = characterRepository.findByUserId(userPrincipal.getId()).orElseThrow(() -> new IllegalArgumentException("캐릭터를 찾을 수 없습니다."));
List<Item> items = character.getItems();
List<Item> itemList = null;

switch (category) {
case "hair":
// item_type이 HAIR인 item만 필터링
itemList = items.stream()
.filter(item -> item.getItemType().equals(HAIR))
.toList();
break;

case "face":
// item_type이 EYE, FACECOLOR인 item만 필터링
itemList = items.stream()
.filter(item -> item.getItemType().equals(EYE) || item.getItemType().equals(FACECOLOR))
.toList();
break;


case "fashion":
// item_type이 HEAD, GLASSES, CLOTHES인 item만 필터링
itemList = items.stream()
.filter(item -> item.getItemType().equals(HEAD) || item.getItemType().equals(GLASSES) || item.getItemType().equals(CLOTHES))
.toList();
break;

case "background":
// item_type이 BACKGROUND인 item만 필터링
itemList = items.stream()
.filter(item -> item.getItemType().equals(BACKGROUND))
.toList();
break;
}

List<CategoryItemRes> categoryItemRes=itemList.stream().map(item -> CategoryItemRes.builder()
.itemId(item.getId())
.itemImage(itemImageRepository.findItemImageByItem(item).getItemImageUrl())
.itemName(item.getItemName())
.itemType(item.getItemType())
// 장착 가능 여부 -> 캐릭터의 레벨이 아이템의 필요 레벨보다 높거나 같으면 장착 가능
.ableToEquip(character.getLevel() >= item.getRequiredLevel())
.isEquipped(item.isEquipped())
.requiredLevel(item.getRequiredLevel())
.build()).toList();


CategoryItemListRes categoryItemListRes = CategoryItemListRes.builder()
.categoryItemList(categoryItemRes)
.build();

ApiResponse apiResponse = ApiResponse.builder()
.check(true)
.information(categoryItemListRes)
.build();

return ResponseEntity.ok(apiResponse);

}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,72 @@
package com.noplanb.domain.item.controller;

import com.noplanb.domain.item.dto.response.CategoryItemListRes;
import com.noplanb.domain.item.application.ItemService;
import com.noplanb.global.config.security.token.CurrentUser;
import com.noplanb.global.config.security.token.UserPrincipal;
import com.noplanb.global.payload.ErrorResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequiredArgsConstructor
@RequestMapping("/api/v1")
@RequestMapping("/api/v1/items")
@Tag(name = "ItemController", description = "ItemControllerController입니다.")
public class ItemController {

private final ItemService itemService;

@Operation(summary = "헤어 카테고리 아이템 조회 API", description = "헤어 카테고리에 해당하는 아이템 목록을 조회하는 API입니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "헤어 아이템 목록 조회 성공", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = CategoryItemListRes.class) ) } ),
@ApiResponse(responseCode = "400", description = "헤어 아이템 목록 조회 실패", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class) ) } ),
})
@GetMapping("/hair")
public ResponseEntity<?> getHairItemList(@Parameter(description = "Access Token을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal){
return itemService.getHairItemList(userPrincipal);
}


@Operation(summary = "얼굴 카테고리 아이템 조회 API", description = "얼굴 카테고리에 해당하는 아이템 목록을 조회하는 API입니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "얼굴 아이템 목록 조회 성공", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = CategoryItemListRes.class) ) } ),
@ApiResponse(responseCode = "400", description = "얼굴 아이템 목록 조회 실패", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class) ) } ),
})
@GetMapping("/face")
public ResponseEntity<?> getFaceItemList(@Parameter(description = "Access Token을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal){
return itemService.getFaceItemList(userPrincipal);
}



@Operation(summary = "패션 카테고리 아이템 조회 API", description = "패션 카테고리에 해당하는 아이템 목록을 조회하는 API입니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "패션 아이템 목록 조회 성공", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = CategoryItemListRes.class) ) } ),
@ApiResponse(responseCode = "400", description = "패션 아이템 목록 조회 실패", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class) ) } ),
})
@GetMapping("/fashion")
public ResponseEntity<?> getFashionItemList(@Parameter(description = "Access Token을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal){
return itemService.getFashionItemList(userPrincipal);
}

@Operation(summary = "배경 카테고리 아이템 조회 API", description = "배경 카테고리에 해당하는 아이템 목록을 조회하는 API입니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "배경 아이템 목록 조회 성공", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = CategoryItemListRes.class) ) } ),
@ApiResponse(responseCode = "400", description = "배경 아이템 목록 조회 실패", content = { @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class) ) } ),
})
@GetMapping("/background")
public ResponseEntity<?> getBackgroundItemList(@Parameter(description = "Access Token을 입력해주세요.", required = true) @CurrentUser UserPrincipal userPrincipal){
return itemService.getBackgroundItemList(userPrincipal);
}

}
2 changes: 1 addition & 1 deletion src/main/java/com/noplanb/domain/item/domain/Item.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class Item extends BaseEntity {
@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
private String item_name;
private String itemName;
@Enumerated(EnumType.STRING)
private ItemType itemType;
private boolean isEquipped;
Expand Down
Empty file.
16 changes: 14 additions & 2 deletions src/main/java/com/noplanb/domain/item/domain/ItemType.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
package com.noplanb.domain.item.domain;

public enum ItemType {
HEAD, FACE, CLOTHES, BACKGROUND,
FACE_COLOR, HAIR, EYE, WEAR
// 카테고리-헤어
HAIR, // 헤어스타일

// 카테고리 - 얼굴
EYE, // 눈
FACECOLOR, // 피부색

// 카테고리 - 패션
HEAD, // 모자
GLASSES, // 안경
CLOTHES, // 옷

// 카테고리 - 배경
BACKGROUND //배경
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.noplanb.domain.item.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class CategoryItemListRes {
@Schema(type = "List", description = "카테고리 내 아이템 정보들을 담은 리스트")
List<CategoryItemRes> categoryItemList;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.noplanb.domain.item.dto.response;


import com.noplanb.domain.item.domain.ItemType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class CategoryItemRes {
@Schema(type = "Long", example = "10", description = "아이템 ID")
private Long itemId;

@Schema(type = "String", example = "베레모", description = "아이템 이름")
private String itemName;

@Schema(type = "String", example = "베레모.png", description = "아이템 이미지")
private String itemImage;

@Schema(type = "String", example = "모자", description = "아이템 타입")
private ItemType itemType;

@Schema(type = "boolean", example = "false", description = "장착 가능여부 ( = 잠금해제여부)")
private boolean ableToEquip;

@Schema(type = "boolean", example = "false", description = "장착 여부")
private boolean isEquipped;

@Schema(type = "Long", example = "20", description = "필요 레벨")
private Long requiredLevel;

}
12 changes: 12 additions & 0 deletions src/main/java/com/noplanb/domain/user/application/UserService.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.noplanb.domain.user.application;

import com.noplanb.domain.user.domain.User;
import com.noplanb.domain.user.dto.response.MyAccountRes;
import com.noplanb.domain.user.repository.UserRepository;
import com.noplanb.global.config.security.token.UserPrincipal;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -25,4 +28,13 @@ public Optional<User> findByEmail(String email) {
return userRepository.findByEmail(email);
}

public ResponseEntity<?> getMyAccount(UserPrincipal userPrincipal) {
User user=userRepository.findById(userPrincipal.getId()).orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다."));

MyAccountRes myAccountRes = MyAccountRes.builder()
.email(user.getEmail())
.build();
return ResponseEntity.ok(myAccountRes);
}

}
Loading

0 comments on commit e9904d7

Please sign in to comment.