Skip to content

Commit 5283f21

Browse files
Merge branch 'main' into feat/#117
2 parents 0bdb5d9 + 93e2482 commit 5283f21

33 files changed

Lines changed: 455 additions & 31 deletions

.github/workflows/ci.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ jobs:
3838
KAKAO_CLIENT_SECRET: ${{ secrets.KAKAO_CLIENT_SECRET }}
3939
KAKAO_REDIRECT_URI: ${{ secrets.KAKAO_REDIRECT_URI }}
4040

41+
GOOGLE_CLIENT_ID: ${{ secrets.GOOGLE_CLIENT_ID }}
42+
GOOGLE_CLIENT_SECRET: ${{ secrets.GOOGLE_CLIENT_SECRET }}
43+
GOOGLE_REDIRECT_URI: ${{ secrets.GOOGLE_REDIRECT_URI }}
44+
4145
steps:
4246
- name: Checkout
4347
uses: actions/checkout@v4

src/main/java/com/back/web7_9_codecrete_be/domain/artists/controller/ArtistsController.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.back.web7_9_codecrete_be.domain.artists.dto.request.UpdateRequest;
66
import com.back.web7_9_codecrete_be.domain.artists.dto.response.ArtistListResponse;
77
import com.back.web7_9_codecrete_be.domain.artists.dto.response.ArtistDetailResponse;
8+
import com.back.web7_9_codecrete_be.domain.artists.dto.response.ConcertListByArtistResponse;
89
import com.back.web7_9_codecrete_be.domain.artists.dto.response.SearchResponse;
910
import com.back.web7_9_codecrete_be.domain.artists.service.ArtistService;
1011
import com.back.web7_9_codecrete_be.domain.artists.service.ArtistEnrichService;
@@ -115,28 +116,41 @@ public RsData<Void> deleteArtistLikes(
115116
return RsData.success("아티스트 찜 해제 성공", null);
116117
}
117118

118-
@Operation(summary = "개인화된 공연 리스트 생성", description = "유저가 찜한 아티스트를 기반으로 공연 리스트를 생성합니다.")
119-
@PostMapping("/list")
120-
public void concertList() {}
119+
@Operation(summary = "아티스트 공연 기록 저장", description = "아티스트 id 와 공연 id 를 받아 해당 아티스트의 공연 기록을 저장합니다.")
120+
@PostMapping("/link/{artistId}/{concertId}")
121+
public RsData<Void> saveConcertArtist(
122+
@PathVariable Long artistId,
123+
@PathVariable Long concertId
124+
) {
125+
artistService.linkArtistConcert(artistId, concertId);
126+
return RsData.success("아티스트 공연 기록 저장 성공", null);
127+
}
128+
129+
@Operation(summary = "개인화된 공연 리스트 생성", description = "유저가 찜한 아티스트들의 공연 리스트를 조회합니다. 로그인한 유저만 가능합니다.")
130+
@GetMapping("/list")
131+
public RsData<List<ConcertListByArtistResponse>> concertList() {
132+
User user = rq.getUser();
133+
return RsData.success("찜한 아티스트 공연 리스트 조회 성공", artistService.getConcertList(user.getId()));
134+
}
121135

122-
@Operation(summary = "아티스트 인기 순위", description = "Spotify 인기도를 바탕으로 아티스트 인기 순위 랭킹을 제공합니다.")
136+
@Operation(summary = "아티스트 인기 순위(구현 전)", description = "Spotify 인기도를 바탕으로 아티스트 인기 순위 랭킹을 제공합니다.")
123137
@GetMapping("/ranking")
124138
public void artistRanking() {}
125139

126-
@Operation(summary = "장르 기반 아티스트 추천", description = "찜한 장르를 기반으로 아티스트 추천 리스트를 제공합니다.")
140+
@Operation(summary = "장르 기반 아티스트 추천(구현 전)", description = "찜한 장르를 기반으로 아티스트 추천 리스트를 제공합니다.")
127141
@GetMapping("/recommendation/{genreId}")
128142
public void recommendArtist(
129143
@PathVariable Long genreId
130144
) {}
131145

132-
@Operation(summary = "공연 셋리스트 생성", description = "사용자가 공연 셋리스트를 생성합니다.")
146+
@Operation(summary = "공연 셋리스트 생성(구현 전)", description = "사용자가 공연 셋리스트를 생성합니다.")
133147
@PostMapping("/setlist/{concertId}/{artistId}")
134148
public void makeSetlist(
135149
@PathVariable Long concertId,
136150
@PathVariable Long artistId
137151
) {}
138152

139-
@Operation(summary = "공연 셋리스트 조회", description = "다른 사용자들이 생성한 셋리스트를 조회합니다.")
153+
@Operation(summary = "공연 셋리스트 조회(구현 전)", description = "다른 사용자들이 생성한 셋리스트를 조회합니다.")
140154
@GetMapping("/setlist/{concertId}/{artistId}")
141155
public void getSetlist(
142156
@PathVariable Long concertId,
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.back.web7_9_codecrete_be.domain.artists.dto.response;
2+
3+
import com.back.web7_9_codecrete_be.domain.concerts.entity.Concert;
4+
5+
import java.time.LocalDate;
6+
7+
public record ConcertListByArtistResponse(
8+
String concertName,
9+
LocalDate startDate,
10+
String concertPlace
11+
) {
12+
public static ConcertListByArtistResponse from(Concert concert) {
13+
return new ConcertListByArtistResponse(
14+
concert.getName(),
15+
concert.getStartDate(),
16+
concert.getConcertPlace().getPlaceName()
17+
);
18+
}
19+
}

src/main/java/com/back/web7_9_codecrete_be/domain/artists/entity/ArtistLike.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.back.web7_9_codecrete_be.domain.users.entity.User;
44
import jakarta.persistence.*;
5+
import lombok.AccessLevel;
56
import lombok.Getter;
67
import lombok.NoArgsConstructor;
78
import org.springframework.data.annotation.CreatedDate;
@@ -12,7 +13,7 @@
1213

1314
@Entity
1415
@Getter
15-
@NoArgsConstructor
16+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
1617
@EntityListeners(AuditingEntityListener.class)
1718
@Table(name = "artist_like")
1819
public class ArtistLike {
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package com.back.web7_9_codecrete_be.domain.artists.entity;
22

3+
import com.back.web7_9_codecrete_be.domain.concerts.entity.Concert;
34
import jakarta.persistence.*;
5+
import lombok.AccessLevel;
46
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
58

69
@Entity
710
@Getter
11+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
812
@Table(name = "concert_artist")
913
public class ConcertArtist {
1014
@Id
@@ -13,11 +17,15 @@ public class ConcertArtist {
1317
private long id;
1418

1519
@ManyToOne(fetch = FetchType.LAZY)
20+
@JoinColumn(name = "artist_id", nullable = false)
1621
private Artist artist;
1722

18-
// TODO : 추후 concert entity 보고 확인 예정 우선 주석 처리
19-
/*
2023
@ManyToOne(fetch = FetchType.LAZY)
24+
@JoinColumn(name = "concert_id", nullable = false)
2125
private Concert concert;
22-
*/
26+
27+
public ConcertArtist(Artist artist, Concert concert) {
28+
this.artist = artist;
29+
this.concert = concert;
30+
}
2331
}

src/main/java/com/back/web7_9_codecrete_be/domain/artists/repository/ArtistLikeRepository.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,22 @@
44
import com.back.web7_9_codecrete_be.domain.artists.entity.ArtistLike;
55
import com.back.web7_9_codecrete_be.domain.users.entity.User;
66
import org.springframework.data.jpa.repository.JpaRepository;
7+
import org.springframework.data.jpa.repository.Query;
8+
import org.springframework.data.repository.query.Param;
79
import org.springframework.stereotype.Repository;
810

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

1114
@Repository
1215
public interface ArtistLikeRepository extends JpaRepository<ArtistLike, Long> {
1316
long countByArtistId(Long artistId);
1417
boolean existsByArtistAndUser(Artist artist, User user);
1518
Optional<ArtistLike> findByArtistAndUser(Artist artist, User user);
19+
@Query("""
20+
select al.artist.id
21+
from ArtistLike al
22+
where al.user.id = :userId
23+
""")
24+
List<Long> findArtistIdsByUserId(@Param("userId") Long userId);
1625
}

src/main/java/com/back/web7_9_codecrete_be/domain/artists/service/ArtistService.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,17 @@
44
import com.back.web7_9_codecrete_be.domain.artists.dto.response.ArtistListResponse;
55
import com.back.web7_9_codecrete_be.domain.artists.dto.response.ArtistDetailResponse;
66
import com.back.web7_9_codecrete_be.domain.artists.dto.response.SearchResponse;
7-
import com.back.web7_9_codecrete_be.domain.artists.entity.Artist;
8-
import com.back.web7_9_codecrete_be.domain.artists.entity.ArtistLike;
9-
import com.back.web7_9_codecrete_be.domain.artists.entity.ArtistType;
10-
import com.back.web7_9_codecrete_be.domain.artists.entity.Genre;
7+
import com.back.web7_9_codecrete_be.domain.artists.entity.*;
118
import com.back.web7_9_codecrete_be.domain.artists.repository.ArtistRepository;
129
import com.back.web7_9_codecrete_be.domain.artists.repository.ArtistLikeRepository;
10+
import com.back.web7_9_codecrete_be.domain.artists.repository.ConcertArtistRepository;
11+
import com.back.web7_9_codecrete_be.domain.artists.dto.response.ConcertListByArtistResponse;
12+
import com.back.web7_9_codecrete_be.domain.concerts.entity.Concert;
13+
import com.back.web7_9_codecrete_be.domain.concerts.repository.ConcertRepository;
14+
import com.back.web7_9_codecrete_be.domain.concerts.service.ConcertService;
1315
import com.back.web7_9_codecrete_be.domain.users.entity.User;
1416
import com.back.web7_9_codecrete_be.global.error.code.ArtistErrorCode;
1517
import com.back.web7_9_codecrete_be.global.error.exception.BusinessException;
16-
import com.back.web7_9_codecrete_be.global.rq.Rq;
1718
import lombok.AccessLevel;
1819
import org.springframework.transaction.annotation.Transactional;
1920
import lombok.RequiredArgsConstructor;
@@ -29,6 +30,9 @@ public class ArtistService {
2930
private final ArtistRepository artistRepository;
3031
private final GenreService genreService;
3132
private final ArtistLikeRepository artistLikeRepository;
33+
private final ConcertArtistRepository concertArtistRepository;
34+
private final ConcertRepository concertRepository;
35+
private final ConcertService concertService;
3236

3337
@Transactional(readOnly = true)
3438
public Artist findArtist(Long artistId) {
@@ -153,4 +157,29 @@ public void deleteLikeArtist(Long artistId, User user) {
153157
artist.decreaseLikeCount();
154158
}
155159

160+
@Transactional
161+
public void linkArtistConcert(Long artistId, Long concertId) {
162+
Artist artist = findArtist(artistId);
163+
// TODO: 멘토링 질문 남겨놓은 기능이라, 멘토링 후 구현 방향 확정되면 함수 선언 후 Service 사용 예정. 현재는 임시로 Repository 사용
164+
Concert concert = concertRepository.findById(concertId)
165+
.orElseThrow();
166+
concertArtistRepository.save(new ConcertArtist(artist, concert));
167+
}
168+
169+
@Transactional(readOnly = true)
170+
public List<ConcertListByArtistResponse> getConcertList(Long userId) {
171+
List<Long> artistIds =
172+
artistLikeRepository.findArtistIdsByUserId(userId);
173+
174+
// 찜한 아티스트가 없는 경우 빈 배열 반환 -> 예외 처리(Error 던지기) 안 함
175+
if (artistIds.isEmpty()) {
176+
return List.of();
177+
}
178+
List<Concert> concerts = concertService.findConcertsByArtistIds(artistIds);
179+
return concerts.stream()
180+
.map(ConcertListByArtistResponse::from)
181+
.toList();
182+
}
183+
184+
156185
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.back.web7_9_codecrete_be.domain.auth.dto.google;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.Getter;
5+
6+
@Getter
7+
public class GoogleTokenResponse {
8+
9+
@JsonProperty("access_token")
10+
private String accessToken;
11+
12+
@JsonProperty("expires_in")
13+
private int expiresIn;
14+
15+
@JsonProperty("token_type")
16+
private String tokenType;
17+
18+
@JsonProperty("scope")
19+
private String scope;
20+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.back.web7_9_codecrete_be.domain.auth.dto.google;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
6+
@Getter
7+
@AllArgsConstructor
8+
public class GoogleUserInfo {
9+
private String socialId;
10+
private String email;
11+
private String nickname;
12+
private String profileImageUrl;
13+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.back.web7_9_codecrete_be.domain.auth.dto.google;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.Getter;
5+
6+
@Getter
7+
public class GoogleUserResponse {
8+
9+
private String id;
10+
private String email;
11+
private String name;
12+
13+
@JsonProperty("picture")
14+
private String profileImageUrl;
15+
16+
public GoogleUserInfo toUserInfo() {
17+
return new GoogleUserInfo(
18+
id,
19+
email,
20+
name,
21+
profileImageUrl
22+
);
23+
}
24+
}

0 commit comments

Comments
 (0)