Skip to content

Commit

Permalink
Merge branch 'dev' into fe/dev/feat_admin_dark/#1649
Browse files Browse the repository at this point in the history
  • Loading branch information
gykoh42 authored Oct 25, 2024
2 parents b1415b8 + 0013d44 commit 601939e
Show file tree
Hide file tree
Showing 107 changed files with 1,508 additions and 812 deletions.
46 changes: 46 additions & 0 deletions .github/ISSUE_TEMPLATE/ui_improvement.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: "UI 개선 건의"
description: UI 개선 건의 작성 기본 양식입니다.
labels: ["ui"]
body:
- type: markdown
attributes:
value: |
작성 예시 : "[FE] 지도-E/V 버튼 눌렀을때 나타나는 로고 색 다크모드 적용"
- type: textarea
id: ui-description
attributes:
label: UI 문제점 설명
description: 문제가 언제/어떻게 발생했는지 명확하게 적어주세요.
placeholder: 설명을 적어주세요.
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: 재현 방법
description: 문제가 재현되는 상황을 설명해주세요.
placeholder: 설명을 적어주세요.
validations:
required: true
- type: textarea
id: improvement
attributes:
label: 기대하는 UI
description: 기대하는 UI에 대해서 설명해주세요.
placeholder: 설명을 적어주세요.
validations:
required: true
- type: textarea
id: system-info
attributes:
label: 시스템 환경 (선택 사항)
description: 현재 버그가 발생한 시스템 환경을 적어주세요.
render: shell
placeholder: OS, 브라우저 등을 적어주세요.
validations:
required: false
- type: textarea
id: additional-context
attributes:
label: 추가 건의사항
description: Cabi에 바라시는 점이나, 하시고 싶은 말씀을 적어주세요.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@
<br/>

## 🕸️ 인프라 구조도
![Untitled](https://github.com/innovationacademy-kr/Cabi/assets/83565255/165c1529-6164-4988-9495-6bc2ba3ef0ab)

![Untitled](https://github.com/innovationacademy-kr/Cabi/assets/83565255/165c1529-6164-4988-9495-6bc2ba3ef0ab)

## 🛠 기술 스택

Expand Down Expand Up @@ -175,6 +175,9 @@
| [ 🐶 surlee](https://github.com/Elineely) | [ 🐣 hyowchoi](https://github.com/chyo1/) | [ 👽 sohyupar](https://github.com/saewoo1) | [🦝 jimchoi](https://github.com/jimchoi9) | [ 🛼 jeekim](https://github.com/jnkeniaem) | [🍾 miyu](https://github.com/Minkyu01) | [🧸 gykoh](https://github.com/gykoh42) |
| ----------------------------------------- | ----------------------------------------- | ------------------------------------------ | ----------------------------------------- | ------------------------------------------ | -------------------------------------- | -------------------------------------- |

| [ 🐰 jihykim2](https://github.com/jihyunk03) | [⛄️ seonmiki](https://github.com/seonmiki) | [ 🎱 junsbae ](https://github.com/wet6123) |
| -------------------------------------------- | ------------------------------------------- | ------------------------------------------ |

| <a href="https://github.com/innovationacademy-kr"><img src="https://img.shields.io/badge/42Seoul-000000?style=flat-square&logo=42&logoColor=white" /></a> |
| --------------------------------------------------------------------------------------------------------------------------------------------------------- |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
import org.ftclub.cabinet.item.service.ItemQueryService;
import org.ftclub.cabinet.item.service.ItemRedisService;
import org.ftclub.cabinet.mapper.ItemMapper;
import org.ftclub.cabinet.utils.lock.LockUtil;
import org.ftclub.cabinet.user.service.UserCommandService;
import org.ftclub.cabinet.user.service.UserQueryService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
Expand All @@ -35,6 +36,8 @@ public class AdminItemFacadeService {
private final ItemMapper itemMapper;

private final ItemRedisService itemRedisService;
private final UserCommandService userCommandService;
private final UserQueryService userQueryService;

@Transactional
public void createItem(Integer Price, Sku sku, ItemType type) {
Expand All @@ -44,16 +47,18 @@ public void createItem(Integer Price, Sku sku, ItemType type) {
@Transactional
public void assignItem(List<Long> userIds, Sku sku) {
Item item = itemQueryService.getBySku(sku);
Long price = item.getPrice();
LocalDateTime now = null;
if (item.getPrice() > 0) {
if (price > 0) {
now = LocalDateTime.now();
userIds.forEach(userId -> LockUtil.lockRedisCoin(userId, () -> {
long coinAmount = itemRedisService.getCoinAmount(userId);
userIds.forEach(userId -> {
long coinAmount = userQueryService.getUser(userId).getCoin();
itemRedisService.saveCoinCount(userId, coinAmount + item.getPrice());

long totalCoinSupply = itemRedisService.getTotalCoinSupply();
itemRedisService.saveTotalCoinSupply(totalCoinSupply + item.getPrice());
}));
userCommandService.updateCoinAmount(userId, price);
});
}
itemHistoryCommandService.createItemHistories(userIds, item.getId(), now);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ public void endUserLent(List<Long> userIds) {
LocalDateTime now = LocalDateTime.now();
List<LentHistory> lentHistories =
lentQueryService.findUserActiveLentHistoriesInCabinetForUpdate(userIds.get(0));
System.out.println("lentHistories = " + lentHistories);
if (lentHistories.isEmpty()) {
Long cabinetId = lentRedisService.findCabinetJoinedUser(userIds.get(0));
if (cabinetId != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Duration;
import java.util.Objects;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -26,7 +27,8 @@ public class FCMTokenRedis {
*/
public <T> Optional<T> findByKey(String key, Class<T> type) {
String serializedValue = redisTemplate.opsForValue().get(key + KEY_PREFIX);
if (serializedValue == null) {
final String NULL = "null";
if (Objects.isNull(serializedValue) || serializedValue.equals(NULL)) {
return Optional.empty();
}
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ public void handleUserLogin(HttpServletRequest req, HttpServletResponse res, Str
FtProfile profile = userOauthService.getProfileByCode(code);
User user = userQueryService.findUser(profile.getIntraName())
.orElseGet(() -> userCommandService.createUserByFtProfile(profile));
// 블랙홀이 API에서 가져온 날짜와 다르다면 갱신
if (!user.isSameBlackholedAt(profile.getBlackHoledAt())) {
userCommandService.updateUserBlackholeStatus(user.getId(), profile.getBlackHoledAt());
}
String token = tokenProvider.createUserToken(user, LocalDateTime.now());
Cookie cookie = cookieManager.cookieOf(TokenProvider.USER_TOKEN_NAME, token);
cookieManager.setCookieToClient(res, cookie, "/", req.getServerName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public List<CabinetsPerSectionResponseDto> getCabinetsPerSection(String building

// 층, 건물에 따른 유저가 알람 등록한 section 조회
Set<String> unsetAlarmSection =
sectionAlarmQueryService.getUnsentAlarm(userId, building, floor).stream()
sectionAlarmQueryService.findUnsentAlarm(userId, building, floor).stream()
.map(alarm -> alarm.getCabinetPlace().getLocation().getSection())
.collect(Collectors.toSet());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ public enum ExceptionStatus {
CLUB_HAS_LENT_CABINET(HttpStatus.NOT_ACCEPTABLE, "대여 중인 사물함을 반납 후 삭제할 수 있습니다."),
HANEAPI_ERROR(HttpStatus.BAD_GATEWAY, "24HANE API 통신에 에러가 있습니다."),
EXTENSION_NOT_FOUND(HttpStatus.BAD_REQUEST, "연장권이 존재하지 않습니다."),
EXTENSION_LENT_DELAYED(HttpStatus.FORBIDDEN, "연장권은 연체된 사물함에 사용할 수 없습니다."),
EXTENSION_SOLO_IN_SHARE_NOT_ALLOWED(HttpStatus.UNAUTHORIZED, "연장권은 1명일 때 사용할 수 없습니다."),
EXTENSION_LENT_DELAYED(HttpStatus.UNAUTHORIZED, "연장권은 연체된 사물함에 사용할 수 없습니다."),
MAIL_BAD_GATEWAY(HttpStatus.BAD_GATEWAY, "메일 전송 중 에러가 발생했습니다"),
SLACK_REQUEST_BAD_GATEWAY(HttpStatus.BAD_GATEWAY, "슬랙 인증 중 에러가 발생했습니다."),
SLACK_MESSAGE_SEND_BAD_GATEWAY(HttpStatus.BAD_GATEWAY, "슬랙 메세지 전송 중 에러가 발생했습니다."),
Expand All @@ -83,7 +83,8 @@ public enum ExceptionStatus {
NOT_ENOUGH_COIN(HttpStatus.BAD_REQUEST, "보유한 코인이 아이템 가격보다 적습니다."),
INVALID_JWT_TOKEN(HttpStatus.BAD_REQUEST, "토큰이 없거나, 유효하지 않은 JWT 토큰입니다."),
NOT_FOUND_SECTION(HttpStatus.BAD_REQUEST, "사물함 구역 정보를 찾을 수 없습니다."),
ITEM_NOT_OWNED(HttpStatus.BAD_REQUEST, "해당 아이템을 보유하고 있지 않습니다");
ITEM_NOT_OWNED(HttpStatus.BAD_REQUEST, "해당 아이템을 보유하고 있지 않습니다"),
ITEM_USE_DUPLICATED(HttpStatus.FORBIDDEN, "아이템이 중복 사용되었습니다.");

final private int statusCode;
final private String message;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
public enum ItemType {

EXTENSION("연장권",
"현재 대여 중인 사물함의 반납 기한을 3일, 15일 또는 30일 연장할 수 있습니다."),
"현재 대여 중인 사물함의 반납 기한을 3일, 15일 또는 31일 연장할 수 있습니다."),
PENALTY("페널티 감면권",
"사물함 이용 중 발생한 페널티 일수를 감소시켜 사물함 사용 제한 기간을 줄일 수 있습니다."),
SWAP("이사권"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ Page<ItemHistory> findAllByUserIdAndItemIdIn(@Param("userId") Long userId,
+ "JOIN FETCH ih.item i "
+ "WHERE ih.userId = :userId "
+ "AND ih.usedAt IS NOT NULL "
+ "AND i.price < 0 "
+ "AND i.price <= 0 "
+ "ORDER BY ih.usedAt DESC",
countQuery = "SELECT COUNT(ih) "
+ "FROM ItemHistory ih "
+ "JOIN ih.item i "
+ "WHERE ih.userId = :userId "
+ "AND ih.usedAt IS NOT NULL "
+ "AND i.price < 0")
+ "AND i.price <= 0")
Page<ItemHistory> findAllByUserIdOnMinusPriceItemsWithSubQuery(
@Param("userId") Long userId, Pageable pageable);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,9 @@ List<SectionAlarm> findAllByUserIdAndCabinetPlaceAndAlarmedAtIsNull(
@Param("userId") Long userId,
@Param("building") String building,
@Param("floor") Integer floor);

List<SectionAlarm> findAllByUserIdAndCabinetPlaceIdOrderByIdDesc(
@Param("userId") Long userId,
@Param("cabinetPlaceId") Long cabinetPlaceId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
import org.ftclub.cabinet.log.Logging;
import org.ftclub.cabinet.mapper.ItemMapper;
import org.ftclub.cabinet.user.domain.User;
import org.ftclub.cabinet.user.service.UserCommandService;
import org.ftclub.cabinet.user.service.UserQueryService;
import org.ftclub.cabinet.utils.blackhole.manager.BlackholeManager;
import org.ftclub.cabinet.utils.lock.LockUtil;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
Expand All @@ -57,17 +59,20 @@
@Logging(level = LogLevel.DEBUG)
public class ItemFacadeService {

private final ItemMapper itemMapper;
private final ItemQueryService itemQueryService;
private final ItemHistoryQueryService itemHistoryQueryService;
private final ItemHistoryCommandService itemHistoryCommandService;
private final ItemRedisService itemRedisService;
private final ItemPolicyService itemPolicyService;
private final UserQueryService userQueryService;
private final SectionAlarmCommandService sectionAlarmCommandService;
private final UserCommandService userCommandService;
private final CabinetQueryService cabinetQueryService;
private final ItemMapper itemMapper;
private final ItemPolicyService itemPolicyService;
private final ApplicationEventPublisher eventPublisher;
private final SectionAlarmCommandService sectionAlarmCommandService;
private final SectionAlarmQueryService sectionAlarmQueryService;
private final BlackholeManager blackholeManager;

private final ApplicationEventPublisher eventPublisher;

/**
* 모든 아이템 리스트 반환
Expand Down Expand Up @@ -190,7 +195,7 @@ public CoinCollectionRewardResponseDto collectCoinAndIssueReward(Long userId) {
// DB에 코인 저장
Item coinCollect = itemQueryService.getBySku(Sku.COIN_COLLECT);
int reward = (int) (coinCollect.getPrice().longValue());
itemHistoryCommandService.createItemHistory(userId, coinCollect.getId());
itemHistoryCommandService.createCoinItemHistory(userId, coinCollect.getId());

// 출석 일자에 따른 랜덤 리워드 지급
Long coinCollectionCountInMonth =
Expand All @@ -201,21 +206,22 @@ public CoinCollectionRewardResponseDto collectCoinAndIssueReward(Long userId) {
Sku coinSku = itemPolicyService.getRewardSku(randomPercentage);
Item coinReward = itemQueryService.getBySku(coinSku);

itemHistoryCommandService.createItemHistory(userId, coinReward.getId());
itemHistoryCommandService.createCoinItemHistory(userId, coinReward.getId());
reward += coinReward.getPrice();
}

// Redis에 코인 변화량 저장
saveCoinChangeOnRedis(userId, reward);
userCommandService.updateCoinAmount(userId, (long) reward);

return new CoinCollectionRewardResponseDto(reward);
}

private void saveCoinChangeOnRedis(Long userId, final int reward) {
LockUtil.lockRedisCoin(userId, () -> {
// Redis에 유저 리워드 저장
long coins = itemRedisService.getCoinAmount(userId);
itemRedisService.saveCoinCount(userId, coins + reward);
// long coins = itemRedisService.getCoinAmount(userId);
// itemRedisService.saveCoinCount(userId, coins + reward);

// Redis에 전체 코인 발행량 저장
long totalCoinSupply = itemRedisService.getTotalCoinSupply();
Expand All @@ -235,11 +241,11 @@ private void saveCoinChangeOnRedis(Long userId, final int reward) {
public void useItem(Long userId, Sku sku, ItemUseRequestDto data) {
itemPolicyService.verifyDataFieldBySku(sku, data);
User user = userQueryService.getUser(userId);

if (user.isBlackholed()) {
// 이벤트를 발생시켰는데 동기로직이다..?
// TODO: 근데 그 이벤트가 뭘 하는지 이 코드 흐름에서는 알 수 없다..?
eventPublisher.publishEvent(UserBlackHoleEvent.of(user));
throw ExceptionStatus.BLACKHOLED_USER.asServiceException();
}

Item item = itemQueryService.getBySku(sku);
List<ItemHistory> itemInInventory =
itemHistoryQueryService.findUnusedItemsInUserInventory(user.getId(), item.getId());
Expand Down Expand Up @@ -294,7 +300,10 @@ public void purchaseItem(Long userId, Sku sku) {

Item item = itemQueryService.getBySku(sku);
long price = item.getPrice();
long userCoin = itemRedisService.getCoinAmount(userId);

// 유저의 보유 재화량
// long userCoin = itemRedisService.getCoinAmount(userId);
long userCoin = user.getCoin();

// 아이템 Policy 검증
itemPolicyService.verifyOnSale(price);
Expand All @@ -311,10 +320,19 @@ public void purchaseItem(Long userId, Sku sku) {
long totalCoinUsage = itemRedisService.getTotalCoinUsage();
itemRedisService.saveTotalCoinUsage(totalCoinUsage + price);
});
userCommandService.updateCoinAmount(userId, price);
}

@Transactional
public void addSectionAlarm(Long userId, Long cabinetPlaceId) {
verifyDuplicateSection(userId, cabinetPlaceId);
sectionAlarmCommandService.addSectionAlarm(userId, cabinetPlaceId);
}

private void verifyDuplicateSection(Long userId, Long cabinetPlaceId) {
if (sectionAlarmQueryService.findUnsentAlarmDesc(userId,
cabinetPlaceId).isPresent()) {
throw ExceptionStatus.ITEM_USE_DUPLICATED.asServiceException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,9 @@ public void createItemHistories(List<Long> userIds, Long itemId, LocalDateTime u
.collect(Collectors.toList());
itemHistoryRepository.saveAll(itemHistories);
}

public void createCoinItemHistory(Long userId, Long itemId) {
ItemHistory coinCollectItemHistory = ItemHistory.of(userId, itemId, LocalDateTime.now());
itemHistoryRepository.save(coinCollectItemHistory);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,6 @@ public class ItemRedisService {
private final ItemRedis itemRedis;
private final ItemHistoryRepository itemHistoryRepository;

public long getCoinAmount(Long userId) {
String userIdString = userId.toString();
String coinAmount = itemRedis.getCoinAmount(userIdString);
if (coinAmount == null) {
long coin = itemHistoryRepository.findAllByUserId(userId).stream()
.mapToLong(ih -> ih.getItem().getPrice())
.reduce(Long::sum).orElse(0L);
itemRedis.saveCoinAmount(userIdString, Long.toString(coin));
return coin;
}
return Integer.parseInt(coinAmount);
}

public void saveCoinCount(Long userId, long coinCount) {
itemRedis.saveCoinAmount(userId.toString(), String.valueOf(coinCount));
}
Expand Down Expand Up @@ -117,4 +104,21 @@ public Long getCoinCollectionCountInMonth(Long userId) {
}
return Long.parseLong(coinCollectionCount);
}

/**
* Redis에 저장되어있는 현재 User가 가진 Coin 양 반환
*/
@Deprecated
public long getCoinAmount(Long userId) {
String userIdString = userId.toString();
String coinAmount = itemRedis.getCoinAmount(userIdString);
if (coinAmount == null) {
long coin = itemHistoryRepository.findAllByUserId(userId).stream()
.mapToLong(ih -> ih.getItem().getPrice())
.reduce(Long::sum).orElse(0L);
itemRedis.saveCoinAmount(userIdString, Long.toString(coin));
return coin;
}
return Integer.parseInt(coinAmount);
}
}
Loading

0 comments on commit 601939e

Please sign in to comment.