Skip to content

Commit fbe30d5

Browse files
authored
Merge pull request #75 from TeamMemeSphere/develop
Develop 에서 main으로 머지
2 parents 397ae84 + 420b989 commit fbe30d5

File tree

66 files changed

+1120
-237
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1120
-237
lines changed

.github/workflows/deploy.yml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ jobs:
4545
runs-on: ubuntu-latest
4646

4747
steps:
48+
- name: Checkout repository
49+
uses: actions/checkout@v4
50+
4851
- name: Deploy to EC2
4952
env:
5053
EC2_SSH_KEY: ${{ secrets.EC2_SSH_KEY }}
@@ -55,13 +58,21 @@ jobs:
5558
run: |
5659
echo "$EC2_SSH_KEY" > private_key.pem
5760
chmod 600 private_key.pem
58-
61+
62+
mkdir -p ~/.ssh
63+
ssh-keyscan -H $EC2_HOST >> ~/.ssh/known_hosts
64+
chmod 600 ~/.ssh/known_hosts
65+
66+
# EC2로 docker-compose.yml 복사
67+
scp -i private_key.pem docker-compose.yml $EC2_USERNAME@$EC2_HOST:/home/$EC2_USERNAME/docker-compose.yml
68+
5969
ssh -i private_key.pem -o StrictHostKeyChecking=no $EC2_USERNAME@$EC2_HOST "
6070
docker pull $DOCKER_USERNAME/$MY_APP:latest
61-
docker stop $MY_APP || true
62-
docker rm $MY_APP || true
63-
docker run -d -p 8080:8080 --name $MY_APP \
64-
$DOCKER_USERNAME/$MY_APP:latest
71+
72+
docker-compose down || true
73+
74+
docker-compose up -d --remove-orphans
75+
docker image prune -f
6576
"
6677
6778
rm -f private_key.pem

build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ dependencies {
5555
implementation 'org.webjars:sockjs-client:1.0.2'
5656
implementation 'org.webjars:stomp-websocket:2.3.3'
5757
implementation 'org.webjars:jquery:3.1.1-1'
58+
59+
// s3 관련
60+
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
61+
62+
// redis
63+
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
5864
}
5965

6066
tasks.named('test') {

docker-compose.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
services:
2+
redis:
3+
image: redis
4+
container_name: redis
5+
ports:
6+
- "6379:6379"
7+
8+
spring:
9+
image: nimuy99/memesphere
10+
container_name: memesphere
11+
restart: always
12+
ports:
13+
- "8080:8080"
14+
depends_on:
15+
- redis

src/main/java/com/memesphere/domain/chartdata/repository/ChartDataRepository.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,27 @@
55
import org.springframework.data.jpa.repository.EntityGraph;
66
import org.springframework.data.jpa.repository.JpaRepository;
77
import org.springframework.data.jpa.repository.Query;
8+
import org.springframework.data.repository.query.Param;
89

10+
import java.awt.print.Pageable;
11+
import java.math.BigDecimal;
12+
import java.time.LocalDateTime;
913
import java.util.List;
1014

1115
public interface ChartDataRepository extends JpaRepository<ChartData, Long> {
12-
@Query("SELECT SUM(c.volume) FROM ChartData c")
13-
Long findTotalVolume();
16+
@Query("SELECT SUM(c.volume) FROM ChartData c " +
17+
"WHERE c.recordedTime = " +
18+
"(SELECT MAX(c2.recordedTime) FROM ChartData c2 WHERE c2.memeCoin = c.memeCoin)")
19+
BigDecimal findTotalVolume();
1420

15-
@EntityGraph(attributePaths = {"memeCoin"})
16-
List<ChartData> findTop5ByOrderByVolumeDesc();
21+
@Query("SELECT c FROM ChartData c " +
22+
"WHERE c.recordedTime = " +
23+
"(SELECT MAX(c2.recordedTime) FROM ChartData c2 WHERE c2.memeCoin = c.memeCoin) " +
24+
"ORDER BY c.volume DESC LIMIT 5")
25+
List<ChartData> findTop5OrderByVolumeDesc();
26+
27+
@Query("SELECT MAX(c.recordedTime) FROM ChartData c WHERE c.memeCoin.id = 1")
28+
LocalDateTime findRecordedTimeByCoinId1();
1729

1830
List<ChartData> findByMemeCoinOrderByRecordedTimeDesc(MemeCoin memeCoin);
1931
}

src/main/java/com/memesphere/domain/chartdata/scheduler/ChartDataScheduler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class ChartDataScheduler {
2424
private final BinanceQueryService binanceQueryService;
2525
private final MemeCoinQueryService memeCoinQueryService;
2626

27-
@Scheduled(fixedRate = 600000) // 10분 간격 실행
27+
@Scheduled(cron = "0 0/10 * * * ?") // 0, 10, 20, 30, 40, 50분에 실행
2828
@Transactional
2929
public void updateChartData() {
3030
List<MemeCoin> memeCoins = memeCoinRepository.findAll();

src/main/java/com/memesphere/domain/chat/controller/ChatController.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ public class ChatController {
2222

2323
private final ChatService chatService;
2424

25-
// TODO: @AuthenticationPrincipal로 사용자 이름 받아오기
2625
@MessageMapping("/chat/{coin_id}")
2726
@SendTo("/sub/{coin_id}")
2827
public ChatResponse chat(@DestinationVariable("coin_id") Long coin_id,
Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,70 @@
11
package com.memesphere.domain.collection.controller;
22

3+
import com.memesphere.domain.collection.service.CollectionCommandService;
34
import com.memesphere.global.apipayload.ApiResponse;
45
import com.memesphere.domain.collection.entity.Collection;
56
import com.memesphere.domain.collection.dto.response.CollectionPageResponse;
67
import com.memesphere.domain.collection.service.CollectionQueryService;
8+
import com.memesphere.global.apipayload.code.status.ErrorStatus;
9+
import com.memesphere.global.apipayload.exception.GeneralException;
10+
import com.memesphere.global.jwt.CustomUserDetails;
11+
import com.memesphere.global.jwt.TokenProvider;
712
import com.memesphere.global.validation.annotation.CheckPage;
813
import io.swagger.v3.oas.annotations.Operation;
14+
import io.swagger.v3.oas.annotations.Parameter;
15+
import io.swagger.v3.oas.annotations.tags.Tag;
16+
import jakarta.servlet.http.HttpServletRequest;
917
import lombok.RequiredArgsConstructor;
1018
import org.springframework.data.domain.Page;
19+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
1120
import org.springframework.web.bind.annotation.*;
1221
import org.springframework.web.bind.annotation.RestController;
1322
import com.memesphere.domain.collection.converter.CollectionConverter;
1423

24+
@Tag(name="콜렉션", description = "콜렉션 관련 API")
1525
@RestController
1626
@RequiredArgsConstructor
17-
//@RequestMapping("/collection")
1827
public class CollectionRestController {
1928
private final CollectionQueryService collectionQueryService;
29+
private final CollectionCommandService collectionCommandService;
30+
private final TokenProvider tokenProvider;
2031

2132
@GetMapping("/collection")
2233
@Operation(summary = "사용자의 밈코인 콜렉션 모음 조회 API")
2334
public ApiResponse<CollectionPageResponse> getCollectionList (
24-
// @AuthenticationPrincipal User user, // 현재 로그인한 사용자 (아직 구현 x)
35+
@AuthenticationPrincipal CustomUserDetails userDetails, // 현재 로그인한 사용자
2536
@CheckPage @RequestParam(name = "page") Integer page // 페이지 번호
2637
) {
2738
Integer pageNumber = page - 1;
28-
// Long userId = user.getId();
29-
Long userId = 1L;
39+
Long userId = (userDetails == null) ? null : userDetails.getUser().getId();
40+
41+
// 유저를 찾지 못하면(로그인을 안 했으면) 콜렉션 접근 못하도록 에러 처리
42+
if (userId == null) throw new GeneralException(ErrorStatus.USER_NOT_FOUND);
3043

3144
Page<Collection> collectionPage = collectionQueryService.getCollectionPage(userId, pageNumber);
3245
return ApiResponse.onSuccess(CollectionConverter.toCollectionPageDTO(collectionPage));
3346
}
3447

48+
@PostMapping("/collection/{coinId}")
49+
@Operation(summary = "밈코인 콜렉션 등록 API",
50+
description = "코인 Id를 입력하면 사용자의 콜렉션에 등록")
51+
public ApiResponse<String> postCollectCoin (@Parameter(hidden = true) @AuthenticationPrincipal CustomUserDetails customUserDetails,
52+
@PathVariable Long coinId) {
53+
54+
Long userId = customUserDetails.getUser().getId();
55+
56+
return ApiResponse.onSuccess(collectionCommandService.addCollectCoin(userId, coinId));
57+
}
58+
59+
@DeleteMapping("/collection/{coinId}")
60+
@Operation(summary = "밈코인 콜렉션 삭제 API",
61+
description = "코인 Id를 입력하면 사용자의 콜렉션에서 삭제")
62+
public ApiResponse<String> deleteCollectCoin (@Parameter(hidden = true) @AuthenticationPrincipal CustomUserDetails customUserDetails,
63+
@PathVariable Long coinId) {
64+
65+
Long userId = customUserDetails.getUser().getId();
66+
67+
return ApiResponse.onSuccess(collectionCommandService.removeCollectCoin(userId, coinId));
68+
}
69+
3570
}

src/main/java/com/memesphere/domain/collection/converter/CollectionConverter.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,19 @@
55
import com.memesphere.domain.memecoin.entity.MemeCoin;
66
import com.memesphere.domain.collection.dto.response.CollectionPageResponse;
77
import com.memesphere.domain.collection.dto.response.CollectionPreviewResponse;
8+
import com.memesphere.domain.user.entity.User;
89
import org.springframework.data.domain.Page;
910

1011
import java.util.List;
1112
import java.util.stream.Collectors;
1213

1314
public class CollectionConverter {
15+
16+
public static Collection toCollection(User user, MemeCoin coin) {
17+
return Collection.builder()
18+
.user(user).memeCoin(coin).build();
19+
}
20+
1421
public static CollectionPageResponse toCollectionPageDTO(Page<Collection> collectionPage) {
1522
List<CollectionPreviewResponse> collectionItems = collectionPage.getContent().stream()
1623
.map(collection -> toCollectionPreviewDTO(collection))

src/main/java/com/memesphere/domain/collection/entity/Collection.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
@Entity
1212
@Getter
13+
@Builder
1314
@DynamicUpdate
1415
@DynamicInsert
1516
@AllArgsConstructor
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
package com.memesphere.domain.collection.repository;
22

33
import com.memesphere.domain.collection.entity.Collection;
4+
import com.memesphere.domain.memecoin.entity.MemeCoin;
5+
import com.memesphere.domain.user.entity.User;
46
import org.springframework.data.domain.Page;
57
import org.springframework.data.domain.Pageable;
68
import org.springframework.data.jpa.repository.JpaRepository;
79

810
import java.util.List;
11+
import java.util.Optional;
912

1013
public interface CollectionRepository extends JpaRepository<Collection, Long> {
1114
Page<Collection> findAllByUserId(Long userId, Pageable pageable);
1215
List<Collection> findAllByUserId(Long userId);
16+
Optional<Collection> findByUserAndMemeCoin(User user, MemeCoin memeCoin);
1317
}

0 commit comments

Comments
 (0)