Skip to content

Commit

Permalink
Merge pull request #16 from TeamUStory/feat/recommend
Browse files Browse the repository at this point in the history
feat: recommend, rename: like에서 great
  • Loading branch information
yungic authored Aug 5, 2024
2 parents f3f0a21 + ded4ee8 commit 85e17ce
Show file tree
Hide file tree
Showing 31 changed files with 668 additions and 157 deletions.
4 changes: 2 additions & 2 deletions gradlew
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
# command line, Great:
#
# ksh Gradle
#
Expand Down Expand Up @@ -179,7 +179,7 @@ if "$cygwin" || "$msys" ; then
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
/?*) t=${arg#/} t=/${t%%/*} # looks Great a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/com/elice/ustory/UStoryApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableScheduling;

import java.util.TimeZone;

@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
@EnableJpaAuditing
@EnableScheduling
public class UStoryApplication {

@PostConstruct
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/com/elice/ustory/domain/address/Address.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.elice.ustory.domain.address;

import com.elice.ustory.domain.paper.entity.Paper;
import com.elice.ustory.domain.recommand.dto.RecommendCountDTO;
import com.elice.ustory.global.entity.BaseEntity;
import com.elice.ustory.global.exception.ErrorCode;
import com.elice.ustory.global.exception.model.ValidationException;
import jakarta.persistence.Column;
Expand All @@ -20,7 +22,7 @@
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "address")
public class Address {
public class Address extends BaseEntity {

private static final String PARAMETER_TOO_LONG = "%s: 해당 파라미터의 길이가 너무 깁니다.";
private static final String WRONG_COORDINATE_X = "설정한 주소의 X좌표의 값이 잘못되었습니다.";
Expand Down Expand Up @@ -66,6 +68,13 @@ public Address(String city, String store, double coordinateX, double coordinateY
this.coordinateY = validateCoordinateY(coordinateY);
}

public Address(RecommendCountDTO recommendCountDTO) {
this.city = recommendCountDTO.getCity();
this.store = recommendCountDTO.getStore();
this.coordinateX = recommendCountDTO.getCoordinateX();
this.coordinateY = recommendCountDTO.getCoordinateY();
}

/**
* Address 객체 업데이트
*
Expand All @@ -92,6 +101,10 @@ public Address update(String city, String store, double coordinateX, double coor
public void setPaper(Paper paper) {
this.paper = paper;

if (paper == null) {
return;
}

if (paper.getAddress() != this) {
paper.setAddress(this);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.elice.ustory.domain.address;

import com.elice.ustory.domain.recommand.dto.RecommendCountDTO;
import org.springframework.data.domain.Pageable;

import java.time.LocalDateTime;
import java.util.List;

public interface AddressQueryDslRepository {

List<RecommendCountDTO> countEqualAddress();
List<RecommendCountDTO> countEqualAddress(Pageable pageable, LocalDateTime requestTime);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.elice.ustory.domain.address;

import com.elice.ustory.domain.recommand.dto.RecommendCountDTO;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;

import static com.elice.ustory.domain.address.QAddress.address;

@Repository
@RequiredArgsConstructor
public class AddressQueryDslRepositoryImpl implements AddressQueryDslRepository {

private final JPAQueryFactory jpaQueryFactory;

@Override
public List<RecommendCountDTO> countEqualAddress() {

return jpaQueryFactory
.select(Projections.constructor(RecommendCountDTO.class,
address.store,
address.city,
address.coordinateX,
address.coordinateY,
address.id.count()
))
.from(address)
.groupBy(address.store, address.city, address.coordinateX, address.coordinateY)
.orderBy(address.id.count().desc())
.fetch();
}

@Override
public List<RecommendCountDTO> countEqualAddress(Pageable pageable, LocalDateTime requestTime) {

return jpaQueryFactory
.select(Projections.constructor(RecommendCountDTO.class,
address.store,
address.city,
address.coordinateX,
address.coordinateY,
address.id.count()
))
.from(address)
.where(address.createdAt.loe(requestTime))
.groupBy(address.store, address.city, address.coordinateX, address.coordinateY)
.orderBy(address.id.count().desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.elice.ustory.domain.address;

import com.elice.ustory.domain.recommand.dto.RecommendCountDTO;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@AllArgsConstructor
public class AddressRecommendDTO {

private String store;
private String city;
private Double coordinateX;
private Double coordinateY;

public AddressRecommendDTO(RecommendCountDTO recommendCountDTO) {
this.store = recommendCountDTO.getStore();
this.city = recommendCountDTO.getCity();
this.coordinateX = recommendCountDTO.getCoordinateX();
this.coordinateY = recommendCountDTO.getCoordinateY();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
import org.springframework.stereotype.Repository;

@Repository
public interface AddressRepository extends JpaRepository<Address, Long> {
public interface AddressRepository extends JpaRepository<Address, Long>, AddressQueryDslRepository {
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public List<DiaryList> searchDiary(Long userId, Pageable pageable, DiaryCategory
diaryUser.id.users.id.eq(userId)
.and(diaryUser.id.diary.createdAt.loe(dateTime))
.and(categoryEq(diaryCategory))
.and(wordLike(searchWord))
.and(wordGreat(searchWord))
)
.orderBy(diaryUser.id.diary.id.desc())
.offset(pageable.getOffset())
Expand Down Expand Up @@ -169,7 +169,7 @@ private BooleanExpression categoryEq(DiaryCategory diaryCategory) {
return diaryCategory != null ? diaryUser.id.diary.diaryCategory.eq(diaryCategory) : null;
}

private BooleanExpression wordLike(String searchWord) {
private BooleanExpression wordGreat(String searchWord) {
return searchWord != null ? diaryUser.id.diary.name.contains(searchWord) : null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package com.elice.ustory.domain.like;
package com.elice.ustory.domain.great;

import com.elice.ustory.domain.like.dto.LikeCountResponse;
import com.elice.ustory.domain.like.dto.LikeListResponse;
import com.elice.ustory.domain.like.dto.LikeResponse;
import com.elice.ustory.domain.great.dto.GreatCountResponse;
import com.elice.ustory.domain.great.dto.GreatListResponse;
import com.elice.ustory.domain.great.dto.GreatResponse;
import com.elice.ustory.domain.paper.entity.Paper;
import com.elice.ustory.global.exception.dto.ErrorResponse;
import com.elice.ustory.global.jwt.JwtAuthorization;
import com.elice.ustory.global.Validation.PageableValidation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
Expand All @@ -30,15 +28,15 @@

import static com.elice.ustory.global.Validation.PageableValidation.pageValidate;

@Tag(name = "Like API")
@Tag(name = "Great API")
@RestController
@RequestMapping("/papers")
@RequiredArgsConstructor
public class LikeController {
public class GreatController {

private final LikeService likeService;
private final GreatService greatService;

@Operation(summary = "Create Like API", description = "좋아요로 지정한다.")
@Operation(summary = "Create Great API", description = "좋아요로 지정한다.")
@ApiResponses({
@ApiResponse(responseCode = "201", description = "Created", content = @Content(mediaType = "application/json")),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))),
Expand All @@ -47,87 +45,87 @@ public class LikeController {
@ApiResponse(responseCode = "409", description = "Conflict", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "500", description = "Internal Server Error", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class)))
})
@PostMapping("/{paperId}/like")
public ResponseEntity<Void> saveLike(@PathVariable Long paperId,
@PostMapping("/{paperId}/great")
public ResponseEntity<Void> saveGreat(@PathVariable Long paperId,
@JwtAuthorization Long userId) {

likeService.saveLike(userId, paperId);
greatService.saveGreat(userId, paperId);

return ResponseEntity.status(HttpStatus.CREATED).build();
}

@Operation(summary = "Read Papers Liked API", description = "좋아요로 지정된 Paper 리스트를 불러온다. <br> 좋아요가 존재하지 않는 경우 빈리스트를 반환한다.")
@Operation(summary = "Read Papers Greatd API", description = "좋아요로 지정된 Paper 리스트를 불러온다. <br> 좋아요가 존재하지 않는 경우 빈리스트를 반환한다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = LikeListResponse.class)))),
@ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = GreatListResponse.class)))),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "500", description = "Internal Server Error", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class)))
})
@GetMapping("/likes")
public ResponseEntity<List<LikeListResponse>> getLikedPapersByUserId(
@GetMapping("/greats")
public ResponseEntity<List<GreatListResponse>> getGreatdPapersByUserId(
@JwtAuthorization Long userId,
@RequestParam(name = "page", defaultValue = "1") int page,
@RequestParam(name = "size", defaultValue = "20") int size) {

pageValidate(page, size);

List<Paper> papers = likeService.getLikesByUser(userId, page, size);
List<Paper> papers = greatService.getGreatsByUser(userId, page, size);

List<LikeListResponse> result = papers.stream()
.map(LikeListResponse::new)
List<GreatListResponse> result = papers.stream()
.map(GreatListResponse::new)
.toList();

return ResponseEntity.ok(result);
}

@Operation(summary = "Like Check API",
@Operation(summary = "Great Check API",
description = "좋아요가 지정되어있는지 확인한다. <br>" +
"isLiked가 0인 경우 좋아요로 지정되지 않았음을 의미한다. <br>" +
"isLiked가 1인 경우 좋아요로 지정되어 있음을 의미한다.")
"isGreatd가 0인 경우 좋아요로 지정되지 않았음을 의미한다. <br>" +
"isGreatd가 1인 경우 좋아요로 지정되어 있음을 의미한다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = LikeResponse.class)))),
@ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = GreatResponse.class)))),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "500", description = "Internal Server Error", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class)))
})
@GetMapping("/{paperId}/like")
public ResponseEntity<LikeResponse> isPaperLiked(@PathVariable Long paperId,
@JwtAuthorization Long userId) {
@GetMapping("/{paperId}/great")
public ResponseEntity<GreatResponse> isPaperGreatd(@PathVariable Long paperId,
@JwtAuthorization Long userId) {

boolean isLiked = likeService.isPaperLikedByUser(userId, paperId);
boolean isGreatd = greatService.isPaperGreatdByUser(userId, paperId);

return ResponseEntity.ok(new LikeResponse(isLiked));
return ResponseEntity.ok(new GreatResponse(isGreatd));
}

@Operation(summary = "Like Count API",
@Operation(summary = "Great Count API",
description = "해당 페이퍼에서 좋아요의 총 개수를 반환한다. <br>" +
"countLike로 개수를 알 수 있다.")
"countGreat로 개수를 알 수 있다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = "application/json", schema = @Schema(implementation = LikeCountResponse.class))),
@ApiResponse(responseCode = "200", description = "Ok", content = @Content(mediaType = "application/json", schema = @Schema(implementation = GreatCountResponse.class))),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "500", description = "Internal Server Error", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class)))
})
@GetMapping("/{paperId}/count")
public ResponseEntity<LikeCountResponse> countLiked(@PathVariable Long paperId) {
public ResponseEntity<GreatCountResponse> countGreatd(@PathVariable Long paperId) {

int count = likeService.countLikedById(paperId);
int count = greatService.countGreatdById(paperId);

return ResponseEntity.ok(new LikeCountResponse(count));
return ResponseEntity.ok(new GreatCountResponse(count));
}

@Operation(summary = "Delete Like API", description = "좋아요를 해제한다.")
@Operation(summary = "Delete Great API", description = "좋아요를 해제한다.")
@ApiResponses({
@ApiResponse(responseCode = "204", description = "No Content", content = @Content(mediaType = "application/json")),
@ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "404", description = "Not Found", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(responseCode = "500", description = "Internal Server Error", content = @Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponse.class)))
})
@DeleteMapping("/{paperId}/like")
public ResponseEntity<Void> deleteLike(@PathVariable Long paperId,
@DeleteMapping("/{paperId}/great")
public ResponseEntity<Void> deleteGreat(@PathVariable Long paperId,
@JwtAuthorization Long userId) {

likeService.deleteLike(userId, paperId);
greatService.deleteGreat(userId, paperId);

return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
Expand Down
Loading

0 comments on commit 85e17ce

Please sign in to comment.