Skip to content

Commit 7257510

Browse files
Merge pull request #63 from prgrms-web-devcourse-final-project/feat/#41
[Concert] 공연 좋아요 기능 추가 + admin 기능 분리
2 parents 45379bf + 8554f97 commit 7257510

10 files changed

Lines changed: 286 additions & 32 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.back.web7_9_codecrete_be.domain.concerts.controller;
2+
3+
import com.back.web7_9_codecrete_be.domain.concerts.dto.KopisApiDto.concert.ConcertListResponse;
4+
import com.back.web7_9_codecrete_be.domain.concerts.dto.KopisApiDto.concertPlace.ConcertPlaceListResponse;
5+
import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertItem;
6+
import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertUpdateRequest;
7+
import com.back.web7_9_codecrete_be.domain.concerts.service.ConcertService;
8+
import com.back.web7_9_codecrete_be.domain.concerts.service.KopisApiService;
9+
import com.back.web7_9_codecrete_be.global.rsData.RsData;
10+
import io.swagger.v3.oas.annotations.tags.Tag;
11+
import lombok.RequiredArgsConstructor;
12+
import org.springframework.stereotype.Controller;
13+
import org.springframework.web.bind.annotation.*;
14+
15+
@RestController
16+
@RequiredArgsConstructor
17+
@RequestMapping("/api/v1/admin/concerts/")
18+
@Tag(name = "Concerts Admin", description = "공연에 대해서 관리하는 API입니다. ")
19+
public class ConcertAdminController { // todo : 인증 권한 추가하기
20+
private final ConcertService concertService;
21+
private final KopisApiService kopisApiService;
22+
23+
@GetMapping("tests")
24+
public ConcertListResponse tests() {
25+
return kopisApiService.getConcertsList();
26+
}
27+
28+
@GetMapping("totalGetTest")
29+
public ConcertListResponse totalGetTest() throws InterruptedException {
30+
return kopisApiService.setConcertsList();
31+
}
32+
33+
@GetMapping("setConcertPlace")
34+
public ConcertPlaceListResponse setConcertPlace() throws InterruptedException {
35+
return kopisApiService.setConcertPlace();
36+
}
37+
38+
@PatchMapping("updateConcert/{concertId}")
39+
public RsData<ConcertItem> updateConcert(
40+
@PathVariable Long concertId,
41+
@RequestBody ConcertUpdateRequest concertUpdateRequest
42+
){
43+
ConcertItem concertItem = concertService.updateConcert(concertId, concertUpdateRequest);
44+
return RsData.success("공연 정보 수정이 완료되었습니다.",concertItem);
45+
}
46+
47+
@DeleteMapping("deleteConcert/{concertId}")
48+
public RsData<Void> deleteConcert(@PathVariable Long concertId){
49+
concertService.deleteConcert(concertId);
50+
return RsData.success("공연 정보 삭제에 성공하였습니다.",null);
51+
}
52+
}

src/main/java/com/back/web7_9_codecrete_be/domain/concerts/controller/ConcertController.java

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
import com.back.web7_9_codecrete_be.domain.concerts.dto.KopisApiDto.concertPlace.ConcertPlaceListResponse;
55
import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertDetailResponse;
66
import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertItem;
7+
import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertLikeResponse;
78
import com.back.web7_9_codecrete_be.domain.concerts.dto.ticketOffice.TicketOfficeElement;
89
import com.back.web7_9_codecrete_be.domain.concerts.entity.TicketOffice;
910
import com.back.web7_9_codecrete_be.domain.concerts.service.ConcertService;
1011
import com.back.web7_9_codecrete_be.domain.concerts.service.KopisApiService;
12+
import com.back.web7_9_codecrete_be.domain.users.entity.User;
13+
import com.back.web7_9_codecrete_be.global.rq.Rq;
1114
import com.back.web7_9_codecrete_be.global.rsData.RsData;
1215
import io.swagger.v3.oas.annotations.Operation;
1316
import io.swagger.v3.oas.annotations.media.Schema;
@@ -19,10 +22,7 @@
1922
import org.springframework.data.domain.Pageable;
2023
import org.springframework.data.domain.Sort;
2124
import org.springframework.stereotype.Controller;
22-
import org.springframework.web.bind.annotation.GetMapping;
23-
import org.springframework.web.bind.annotation.RequestMapping;
24-
import org.springframework.web.bind.annotation.RequestParam;
25-
import org.springframework.web.bind.annotation.RestController;
25+
import org.springframework.web.bind.annotation.*;
2626

2727
import java.util.List;
2828

@@ -33,45 +33,36 @@
3333
@Tag(name = "Concerts", description = "공연에 대한 정보를 제공하는 API 입니다.")
3434
public class ConcertController {
3535
private final ConcertService concertService;
36-
private final KopisApiService kopisApiService;
37-
38-
@GetMapping("tests")
39-
public ConcertListResponse tests() {
40-
return kopisApiService.getConcertsList();
41-
}
42-
43-
@GetMapping("totalGetTest")
44-
public ConcertListResponse totalGetTest() throws InterruptedException {
45-
return kopisApiService.setConcertsList();
46-
}
47-
48-
@GetMapping("setConcertPlace")
49-
public ConcertPlaceListResponse setConcertPlace() throws InterruptedException {
50-
return kopisApiService.setConcertPlace();
51-
}
36+
private final Rq rq;
5237

5338
@Operation(summary = "공연목록", description = "공연 전체 목록을 조회합니다. 시작일자를 기준으로 오름차순 조회합니다.")
5439
@GetMapping("list")
5540
public RsData<List<ConcertItem>> getList (
56-
@RequestParam
57-
@Schema(description = "page입니다. 일단은 ?page={page} 로 넘기시면 됩니다.", example = "1")
58-
int page
41+
@Schema(description = "페이징 처리 또는 무한 스크롤 구현에 쓸 Pageable 객체입니다.")
42+
Pageable pageable
5943
) {
60-
Pageable pageable = PageRequest.of(page, 10, Sort.by("startDate").ascending());
6144
return RsData.success(concertService.getConcertsList(pageable));
6245
}
6346

6447
@Operation(summary = "다가오는 공연 목록", description = "오늘을 기준으로 다가오는 공연 목록을 조회합니다.")
6548
@GetMapping("upComingList")
6649
public RsData<List<ConcertItem>> getUpComingList (
67-
@RequestParam
68-
@Schema(description = "page입니다. 일단은 ?page={page} 로 넘기시면 됩니다.", example = "1")
69-
int page
50+
@Schema(description = "페이징 처리 또는 무한 스크롤 구현에 쓸 Pageable 객체입니다.")
51+
Pageable pageable
7052
) {
71-
Pageable pageable = PageRequest.of(page, 10);
7253
return RsData.success(concertService.getUpcomingConcertsList(pageable));
7354
}
7455

56+
@Operation(summary = "좋아요 한 공연 조회", description = "좋아요를 누른 공연에 대한 목록을 조회합니다. 저장 날짜를 기준으로 내림차순 정렬로 표시합니다.(최신으로 추가된 목록순입니다.)")
57+
@GetMapping("likedConcertList")
58+
public RsData<List<ConcertItem>> getLikedConcertList (
59+
@Schema(description = "페이징 처리 또는 무한 스크롤 구현에 쓸 Pageable 객체입니다.")
60+
Pageable pageable
61+
){
62+
User user = rq.getUser();
63+
return RsData.success(concertService.getLikedConcertsList(pageable,user));
64+
}
65+
7566
@Operation(summary = "공연 상세 조회", description = "공연에 대한 상세 목록을 조회합니다.")
7667
@GetMapping("concertDetail")
7768
public ConcertDetailResponse getConcertDetail(
@@ -82,6 +73,8 @@ public ConcertDetailResponse getConcertDetail(
8273
return concertService.getConcertDetail(concertId);
8374
}
8475

76+
77+
8578
@Operation(summary = "공연 예매처 조회", description = "공연에 대한 예매처들을 조회합니다.")
8679
@GetMapping("ticketOffices")
8780
public RsData<List<TicketOfficeElement>> getTicketOffices (
@@ -92,4 +85,34 @@ public RsData<List<TicketOfficeElement>> getTicketOffices (
9285
return RsData.success(concertService.getTicketOfficesList(concertId));
9386
}
9487

88+
@Operation(summary = "공연 좋아요 기능", description = "사용자가 마음에 드는 공연에 대해 좋아요를 통해 저장할 수 있습니다.")
89+
@PostMapping("like/{concertId}")
90+
public RsData<Void> likeConcert(
91+
@PathVariable long concertId
92+
) {
93+
User user = rq.getUser();
94+
concertService.likeConcert(concertId, user);
95+
return RsData.success(null);
96+
}
97+
98+
@Operation(summary = "공연 좋아요 해제 기능", description = "좋아요를 해제할 수 있습니다.")
99+
@DeleteMapping("dislike/{concertId}")
100+
public RsData<Void> dislikeConcert(
101+
@PathVariable long concertId
102+
) {
103+
User user = rq.getUser();
104+
concertService.dislikeConcert(concertId, user);
105+
return RsData.success(null);
106+
}
107+
108+
@Operation(summary = "공연 좋아요 여부 확인", description = "좋아요 여부를 확인합니다.")
109+
@GetMapping("isLike/{concertId}")
110+
public RsData<ConcertLikeResponse> isLikeConcert(
111+
@PathVariable long concertId
112+
){
113+
User user = rq.getUser();
114+
return RsData.success(concertService.isLikeConcert(concertId, user));
115+
}
116+
117+
95118
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.back.web7_9_codecrete_be.domain.concerts.dto.concert;
2+
3+
import com.back.web7_9_codecrete_be.domain.concerts.entity.Concert;
4+
import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertLike;
5+
import lombok.Getter;
6+
7+
@Getter
8+
public class ConcertLikeResponse {
9+
private Long concertId;
10+
private Boolean isLike;
11+
12+
public ConcertLikeResponse(Concert concert, Boolean isLike) {
13+
this.concertId = concert.getConcertId();
14+
this.isLike = isLike;
15+
}
16+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.back.web7_9_codecrete_be.domain.concerts.dto.concert;
2+
3+
import lombok.Getter;
4+
5+
import java.time.LocalDate;
6+
7+
@Getter
8+
public class ConcertUpdateRequest {
9+
private Long concertId;
10+
private String name;
11+
private String description;
12+
private Long placeId;
13+
private LocalDate StartDate;
14+
private LocalDate EndDate;
15+
private String posterUrl;
16+
private int maxPrice;
17+
private int minPrice;
18+
}

src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/Concert.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.back.web7_9_codecrete_be.domain.concerts.entity;
22

3+
import com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertUpdateRequest;
34
import jakarta.persistence.*;
45
import lombok.Getter;
56
import lombok.RequiredArgsConstructor;
@@ -90,4 +91,18 @@ public Concert update(ConcertPlace concertPlace, String content, String ticketTi
9091
return this;
9192
}
9293

94+
95+
public Concert update(ConcertUpdateRequest concertUpdateRequest,ConcertPlace concertPlace) {
96+
this.name = concertUpdateRequest.getName();
97+
this.concertPlace = concertPlace;
98+
this.content = concertUpdateRequest.getDescription();
99+
this.maxPrice = concertUpdateRequest.getMaxPrice();
100+
this.minPrice = concertUpdateRequest.getMinPrice();
101+
this.posterUrl = concertUpdateRequest.getPosterUrl();
102+
this.startDate = concertUpdateRequest.getStartDate();
103+
this.endDate = concertUpdateRequest.getEndDate();
104+
this.modifiedDate = LocalDateTime.now();
105+
return this;
106+
}
107+
93108
}

src/main/java/com/back/web7_9_codecrete_be/domain/concerts/entity/ConcertLike.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
import jakarta.persistence.*;
55
import lombok.Getter;
66
import lombok.RequiredArgsConstructor;
7+
import org.hibernate.annotations.CreationTimestamp;
8+
9+
import java.time.LocalDateTime;
710

811
@Entity
912
@Getter
@@ -15,9 +18,17 @@ public class ConcertLike {
1518
@Column(name = "concert_like_id")
1619
private Long concertLikeId;
1720

18-
@ManyToOne
21+
@ManyToOne(fetch = FetchType.LAZY)
1922
private Concert concert;
2023

21-
@ManyToOne
24+
@ManyToOne(fetch = FetchType.LAZY)
2225
private User user;
26+
27+
@CreationTimestamp
28+
private LocalDateTime createdAt;
29+
30+
public ConcertLike(Concert concert, User user) {
31+
this.concert = concert;
32+
this.user = user;
33+
}
2334
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
package com.back.web7_9_codecrete_be.domain.concerts.repository;
22

3+
import com.back.web7_9_codecrete_be.domain.concerts.entity.Concert;
34
import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertLike;
5+
import com.back.web7_9_codecrete_be.domain.users.entity.User;
46
import org.springframework.data.jpa.repository.JpaRepository;
57
import org.springframework.stereotype.Repository;
68

79
@Repository
810
public interface ConcertLikeRepository extends JpaRepository<ConcertLike, Long> {
11+
ConcertLike findConcertLikeByConcertAndUser(Concert concert, User user);
12+
13+
boolean existsConcertLikeByConcertAndUser(Concert concert, User user);
914
}
1015

src/main/java/com/back/web7_9_codecrete_be/domain/concerts/repository/ConcertRepository.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.back.web7_9_codecrete_be.domain.concerts.entity.Concert;
66
import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertPlace;
77
import com.back.web7_9_codecrete_be.domain.concerts.entity.ConcertTime;
8+
import com.back.web7_9_codecrete_be.domain.users.entity.User;
89
import org.springframework.data.domain.Page;
910
import org.springframework.data.domain.Pageable;
1011
import org.springframework.data.jpa.repository.JpaRepository;
@@ -65,6 +66,35 @@ List<ConcertItem> getUpComingConcertItems(
6566
@Param("fromDate") LocalDate fromDate
6667
);
6768

69+
@Query("""
70+
SELECT
71+
new com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertItem(
72+
c.concertId as id,
73+
c.name as name,
74+
c.concertPlace.placeName as placeName,
75+
c.startDate as startDate,
76+
c.endDate as endDate,
77+
c.posterUrl as posterUrl,
78+
c.maxPrice as maxPrice,
79+
c.minPrice as minPrice,
80+
c.viewCount as viewCount,
81+
c.likeCount as likeCount
82+
)
83+
FROM
84+
Concert c,
85+
ConcertLike cl
86+
WHERE
87+
c.concertId = cl.concert.concertId
88+
AND
89+
cl.user.id = :userId
90+
ORDER BY
91+
cl.createdAt
92+
DESC
93+
"""
94+
)
95+
List<ConcertItem> getLikedConcertsList(Pageable pageable,
96+
@Param("userId") Long userId);
97+
6898
@Query("""
6999
SELECT
70100
new com.back.web7_9_codecrete_be.domain.concerts.dto.concert.ConcertDetailResponse(
@@ -86,4 +116,8 @@ List<ConcertItem> getUpComingConcertItems(
86116
c.concertId = :concertId
87117
""")
88118
ConcertDetailResponse getConcertDetailById(@Param("concertId")long concertId);
119+
120+
121+
122+
Concert getConcertByConcertId(Long concertId);
89123
}

0 commit comments

Comments
 (0)