Skip to content

Commit

Permalink
Merge pull request #147 from side-peek/feat/#146-weekly-popular-proje…
Browse files Browse the repository at this point in the history
…cts-controller

지난 주 인기 프로젝트 목록 조회(배너용) 구현
  • Loading branch information
Sehee-Lee-01 authored Mar 13, 2024
2 parents c7c03dc + 01a4440 commit c86b3e7
Show file tree
Hide file tree
Showing 20 changed files with 341 additions and 100 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package sixgaezzang.sidepeek.auth.dto.request;

import static sixgaezzang.sidepeek.auth.exeption.message.AuthErrorMessage.EMAIL_IS_NULL;
import static sixgaezzang.sidepeek.auth.exeption.message.AuthErrorMessage.PASSWORD_IS_NULL;
import static sixgaezzang.sidepeek.auth.exception.message.AuthErrorMessage.EMAIL_IS_NULL;
import static sixgaezzang.sidepeek.auth.exception.message.AuthErrorMessage.PASSWORD_IS_NULL;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package sixgaezzang.sidepeek.auth.dto.request;

import static sixgaezzang.sidepeek.auth.exeption.message.AuthErrorMessage.REFRESH_TOKEN_IS_NULL;
import static sixgaezzang.sidepeek.auth.exception.message.AuthErrorMessage.REFRESH_TOKEN_IS_NULL;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package sixgaezzang.sidepeek.auth.exeption.message;
package sixgaezzang.sidepeek.auth.exception.message;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import sixgaezzang.sidepeek.common.exception.ErrorResponse;
import sixgaezzang.sidepeek.projects.dto.request.CursorPaginationInfoRequest;
import sixgaezzang.sidepeek.projects.dto.request.SaveProjectRequest;
import sixgaezzang.sidepeek.projects.dto.request.UpdateProjectRequest;
import sixgaezzang.sidepeek.projects.dto.response.CursorPaginationResponse;
import sixgaezzang.sidepeek.projects.dto.response.ProjectBannerResponse;
import sixgaezzang.sidepeek.projects.dto.response.ProjectListResponse;
import sixgaezzang.sidepeek.projects.dto.response.ProjectResponse;

Expand All @@ -29,7 +31,29 @@ public interface ProjectControllerDoc {
@ApiResponse(responseCode = "401", description = "UNAUTHORIZED", content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
ResponseEntity<ProjectResponse> save(@Parameter(hidden = true) Long loginId,
SaveProjectRequest request);
SaveProjectRequest request);

@Operation(summary = "프로젝트 상세 조회")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", useReturnTypeSchema = true),
@ApiResponse(responseCode = "404", description = "NOT_FOUND", content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@Parameter(name = "id", description = "조회할 프로젝트 식별자", in = ParameterIn.PATH)
ResponseEntity<ProjectResponse> getById(Long id);

@Operation(summary = "프로젝트 전체 조회")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", useReturnTypeSchema = true)
})
ResponseEntity<CursorPaginationResponse<ProjectListResponse>> getByCondition(
@Parameter(hidden = true) Long loginId,
@Valid @ModelAttribute CursorPaginationInfoRequest pageable);

@Operation(summary = "금주의 인기 프로젝트 조회(배너용)", description = "주간 좋아요 기록을 통해 프로젝트 인기순으로 정렬")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", useReturnTypeSchema = true)
})
ResponseEntity<List<ProjectBannerResponse>> getAllPopularThisWeek();

@Operation(summary = "프로젝트 수정", description = "프로젝트 작성자와 멤버만 수정이 가능합니다.")
@ApiResponses({
Expand All @@ -41,7 +65,7 @@ ResponseEntity<ProjectResponse> save(@Parameter(hidden = true) Long loginId,
})
@Parameter(name = "id", description = "수정할 프로젝트 식별자", in = ParameterIn.PATH)
ResponseEntity<ProjectResponse> update(@Parameter(hidden = true) Long loginId, Long projectId,
UpdateProjectRequest request);
UpdateProjectRequest request);

@Operation(summary = "프로젝트 삭제", description = "프로젝트 작성자만 삭제가 가능합니다.")
@ApiResponses({
Expand All @@ -53,19 +77,4 @@ ResponseEntity<ProjectResponse> update(@Parameter(hidden = true) Long loginId, L
@Parameter(name = "id", description = "삭제할 프로젝트 식별자", in = ParameterIn.PATH)
ResponseEntity<Void> delete(@Parameter(hidden = true) Long loginId, Long projectId);

@Operation(summary = "프로젝트 상세 조회")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", useReturnTypeSchema = true),
@ApiResponse(responseCode = "404", description = "NOT_FOUND", content = @Content(schema = @Schema(implementation = ErrorResponse.class)))
})
@Parameter(name = "id", description = "조회할 프로젝트 식별자", in = ParameterIn.PATH)
ResponseEntity<ProjectResponse> getById(Long id);

@Operation(summary = "프로젝트 전체 조회")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", useReturnTypeSchema = true)
})
ResponseEntity<CursorPaginationResponse<ProjectListResponse>> getByCondition(
@Parameter(hidden = true) Long loginId,
@Valid @ModelAttribute CursorPaginationInfoRequest pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,6 @@ public ResponseEntity<ErrorResponse> handleInvalidAuthenticationException(
.body(errorResponse);
}

@ExceptionHandler(InvalidAuthorityException.class)
public ResponseEntity<ErrorResponse> handleInvalidAuthorityException(
InvalidAuthorityException e) {
ErrorResponse errorResponse = ErrorResponse.of(HttpStatus.FORBIDDEN, e.getMessage());
log.warn(e.getMessage(), e.fillInStackTrace());

return ResponseEntity.status(HttpStatus.FORBIDDEN)
.body(errorResponse);
}

@ExceptionHandler(HttpMessageNotReadableException.class)
public ResponseEntity<ErrorResponse> handleHttpMessageNotReadableException(
HttpMessageNotReadableException e) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package sixgaezzang.sidepeek.common.util.component;

import java.time.LocalDate;
import java.time.LocalDateTime;
import org.springframework.stereotype.Component;

@Component
public class DateTimeProvider {

/**
* 현재 날짜를 반환하는 메서드
*
* @return {@code LocalDate}
*/
public LocalDate getCurrentDate() {
return LocalDate.now();
}

/**
* 현재 날짜, 시간를 반환하는 메서드
*
* @return {@code LocalDateTime}
*/
public LocalDateTime getCurrentDateTime() {
return LocalDateTime.now();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
import java.util.regex.Pattern;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.util.Assert;
import sixgaezzang.sidepeek.common.exception.InvalidAuthenticationException;
import sixgaezzang.sidepeek.common.exception.InvalidAuthorityException;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class ValidationUtils {
Expand Down Expand Up @@ -134,7 +134,7 @@ public static <T> boolean isNullOrEmpty(Collection<T> input) {
public static void validateLoginIdEqualsOwnerId(Long loginId, Long ownerId) {
validateOwnerId(ownerId);
if (!loginId.equals(ownerId)) {
throw new InvalidAuthorityException(OWNER_ID_NOT_EQUALS_LOGIN_ID);
throw new AccessDeniedException(OWNER_ID_NOT_EQUALS_LOGIN_ID);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import jakarta.validation.Valid;
import java.net.URI;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
Expand All @@ -20,6 +21,7 @@
import sixgaezzang.sidepeek.projects.dto.request.SaveProjectRequest;
import sixgaezzang.sidepeek.projects.dto.request.UpdateProjectRequest;
import sixgaezzang.sidepeek.projects.dto.response.CursorPaginationResponse;
import sixgaezzang.sidepeek.projects.dto.response.ProjectBannerResponse;
import sixgaezzang.sidepeek.projects.dto.response.ProjectListResponse;
import sixgaezzang.sidepeek.projects.dto.response.ProjectResponse;
import sixgaezzang.sidepeek.projects.service.ProjectService;
Expand All @@ -46,6 +48,35 @@ public ResponseEntity<ProjectResponse> save(
.body(response);
}

@Override
@GetMapping("/{id}")
public ResponseEntity<ProjectResponse> getById(
@PathVariable Long id
) {
ProjectResponse response = projectService.findById(id);

return ResponseEntity.ok(response);
}

@Override
@GetMapping
public ResponseEntity<CursorPaginationResponse<ProjectListResponse>> getByCondition(
@Login Long loginId,
@Valid @ModelAttribute CursorPaginationInfoRequest pageable
) {
CursorPaginationResponse<ProjectListResponse> responses = projectService.findByCondition(
loginId, pageable);
return ResponseEntity.ok().body(responses);
}

@Override
@GetMapping("/weekly")
public ResponseEntity<List<ProjectBannerResponse>> getAllPopularThisWeek() {
List<ProjectBannerResponse> responses = projectService.findAllPopularLastWeek();

return ResponseEntity.ok(responses);
}

@Override
@PutMapping("/{id}")
public ResponseEntity<ProjectResponse> update(
Expand All @@ -69,25 +100,4 @@ public ResponseEntity<Void> delete(
return ResponseEntity.noContent()
.build();
}

@Override
@GetMapping("/{id}")
public ResponseEntity<ProjectResponse> getById(
@PathVariable Long id
) {
ProjectResponse response = projectService.findById(id);

return ResponseEntity.ok(response);
}

@Override
@GetMapping
public ResponseEntity<CursorPaginationResponse<ProjectListResponse>> getByCondition(
@Login Long loginId,
@Valid @ModelAttribute CursorPaginationInfoRequest pageable
) {
CursorPaginationResponse<ProjectListResponse> responses = projectService.findByCondition(
loginId, pageable);
return ResponseEntity.ok().body(responses);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ public void increaseViewCount() {
this.viewCount++;
}

public void softDelete() {
public void softDelete(LocalDateTime now) {
if (Objects.isNull(this.deletedAt)) {
this.deletedAt = LocalDateTime.now();
this.deletedAt = now;
return;
}
throw new IllegalStateException(PROJECT_ALREADY_DELETED);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package sixgaezzang.sidepeek.projects.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import sixgaezzang.sidepeek.projects.domain.Project;

@Schema(description = "배너용 프로젝트 응답")
@Builder
public record ProjectBannerResponse(
@Schema(description = "프로젝트 식별자", example = "1")
Long id,
@Schema(description = "프로젝트 제목", example = "사이드픽👀")
String name,
@Schema(description = "프로젝트 부제목", example = "요즘 사이드 플젝 뭐함? 사이드픽 \uD83D\uDC40")
String subName,
@Schema(description = "프로젝트 썸네일 이미지 URL", example = "https://sidepeek.image/imageeUrl")
String thumbnailUrl
) {

public static ProjectBannerResponse from(Project project) {
return ProjectBannerResponse.builder()
.id(project.getId())
.name(project.getName())
.subName(project.getSubName())
.thumbnailUrl(project.getThumbnailUrl())
.build();
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package sixgaezzang.sidepeek.projects.repository.project;

import java.time.LocalDate;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import sixgaezzang.sidepeek.projects.dto.request.CursorPaginationInfoRequest;
import sixgaezzang.sidepeek.projects.dto.response.CursorPaginationResponse;
import sixgaezzang.sidepeek.projects.dto.response.ProjectBannerResponse;
import sixgaezzang.sidepeek.projects.dto.response.ProjectListResponse;
import sixgaezzang.sidepeek.users.domain.User;

Expand All @@ -14,12 +16,14 @@ CursorPaginationResponse<ProjectListResponse> findByCondition(
List<Long> likedProjectIds,
CursorPaginationInfoRequest pageable);

List<ProjectBannerResponse> findAllPopularOfPeriod(LocalDate startDate, LocalDate endDate, int count);

Page<ProjectListResponse> findAllByUserJoined(List<Long> likedProjectIds, User user,
Pageable pageable);
Pageable pageable);

Page<ProjectListResponse> findAllByUserLiked(List<Long> likedProjectIds, User user,
Pageable pageable);
Pageable pageable);

Page<ProjectListResponse> findAllByUserCommented(List<Long> likedProjectIds, User user,
Pageable pageable);
Pageable pageable);
}
Loading

0 comments on commit c86b3e7

Please sign in to comment.