Skip to content

Commit

Permalink
[Feature] 프로필 남은 기능들을 구현한다 (#95)
Browse files Browse the repository at this point in the history
* feature: 사용자 이름 중복 검사를 구현한다

* feature: 사용자 공개 범위 조회를 구현한다

* refactor: 사용자 도메인의 응답 DTO에 기본 생성자를 제거한다

* feature: Post에 업로드한 시간을 추가한다

* feature: 트래커 조회를 구현한다

* refactor: 트래커 일수를 설정으로 분리한다

* test: GetTrackerService의 테스트를 작성한다

* fix: 실패하는 테스트를 고친다

- 설정 파일에 새로 추가한 설정을 확인함
  • Loading branch information
vectorch9 authored Nov 6, 2023
1 parent 8748ab1 commit a579d0e
Show file tree
Hide file tree
Showing 20 changed files with 304 additions and 23 deletions.
52 changes: 52 additions & 0 deletions src/main/java/daybyquest/post/application/GetTrackerService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package daybyquest.post.application;

import static java.time.LocalDateTime.now;
import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;

import daybyquest.post.dto.response.TrackerResponse;
import daybyquest.post.query.PostDao;
import daybyquest.post.query.SimplePostData;
import daybyquest.user.domain.Users;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class GetTrackerService {

private final Users users;

private final PostDao postDao;

private final long trackerDays;

public GetTrackerService(final Users users, final PostDao postDao,
@Value("${tracker.days}") final long trackerDays) {
this.users = users;
this.postDao = postDao;
this.trackerDays = trackerDays;
}

@Transactional(readOnly = true)
public TrackerResponse invoke(final Long loginId, final String username) {
final Long userId = users.getUserIdByUsername(username);
final List<SimplePostData> simplePostData = postDao
.findAllBySuccessAndUploadedAtAfter(userId, now().minusDays(trackerDays));
return new TrackerResponse(calculateTracker(simplePostData));
}

private List<Long> calculateTracker(final List<SimplePostData> simplePostData) {
final Map<LocalDate, Long> counts = simplePostData.stream()
.collect(groupingBy((time) -> time.uploadedAt().toLocalDate(), counting()));

return Stream.iterate(LocalDate.now(), date -> date.minusDays(1))
.limit(trackerDays)
.map(time -> counts.getOrDefault(time, 0L)
).toList();
}
}
4 changes: 4 additions & 0 deletions src/main/java/daybyquest/post/domain/Post.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

Expand All @@ -50,6 +51,9 @@ public class Post {
@Column
private Long questId;

@CreatedDate
private LocalDateTime uploadedAt;

@LastModifiedDate
private LocalDateTime updatedAt;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package daybyquest.post.dto.response;

import java.util.List;

public record TrackerResponse(List<Long> tracker) {

}
16 changes: 15 additions & 1 deletion src/main/java/daybyquest/post/presentation/PostQueryApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
import daybyquest.post.application.GetPostByUsernameService;
import daybyquest.post.application.GetPostFromFollowingService;
import daybyquest.post.application.GetPostService;
import daybyquest.post.application.GetTrackerService;
import daybyquest.post.dto.response.PagePostsResponse;
import daybyquest.post.dto.response.PostWithQuestResponse;
import daybyquest.post.dto.response.TrackerResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -22,12 +24,16 @@ public class PostQueryApi {

private final GetPostByUsernameService getPostByUsernameService;

private final GetTrackerService getTrackerService;

public PostQueryApi(final GetPostService getPostService,
final GetPostFromFollowingService getPostFromFollowingService,
final GetPostByUsernameService getPostByUsernameService) {
final GetPostByUsernameService getPostByUsernameService,
final GetTrackerService getTrackerService) {
this.getPostService = getPostService;
this.getPostFromFollowingService = getPostFromFollowingService;
this.getPostByUsernameService = getPostByUsernameService;
this.getTrackerService = getTrackerService;
}

@GetMapping("/post/{postId}")
Expand All @@ -54,4 +60,12 @@ public ResponseEntity<PagePostsResponse> getPostByUsername(final AccessUser acce
page);
return ResponseEntity.ok(response);
}

@GetMapping("/profile/{username}/tracker")
@Authorization
public ResponseEntity<TrackerResponse> getTracker(final AccessUser accessUser,
@PathVariable final String username) {
final TrackerResponse response = getTrackerService.invoke(accessUser.getId(), username);
return ResponseEntity.ok(response);
}
}
3 changes: 3 additions & 0 deletions src/main/java/daybyquest/post/query/PostDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import daybyquest.global.query.LongIdList;
import daybyquest.global.query.NoOffsetIdPage;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;

Expand All @@ -14,4 +15,6 @@ public interface PostDao {
LongIdList findPostIdsByUserId(final Long userId, final Long targetId, final NoOffsetIdPage page);

List<PostData> findAllByIdIn(final Long userId, final Collection<Long> postIds);

List<SimplePostData> findAllBySuccessAndUploadedAtAfter(final Long userId, final LocalDateTime time);
}
13 changes: 13 additions & 0 deletions src/main/java/daybyquest/post/query/PostDaoQuerydslImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static com.querydsl.core.group.GroupBy.list;
import static daybyquest.image.domain.QImage.image;
import static daybyquest.like.domain.QPostLike.postLike;
import static daybyquest.post.domain.PostState.SUCCESS;
import static daybyquest.post.domain.QPost.post;
import static daybyquest.quest.domain.QQuest.quest;
import static daybyquest.relation.domain.QFollow.follow;
Expand All @@ -17,6 +18,7 @@
import daybyquest.global.query.LongIdList;
import daybyquest.global.query.NoOffsetIdPage;
import daybyquest.image.domain.Image;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -107,4 +109,15 @@ public List<PostData> findAllByIdIn(final Long userId, final Collection<Long> po
postDataMap.forEach((id, postData) -> postData.setImages(imageMap.get(id)));
return postDataMap.values().stream().toList();
}

@Override
public List<SimplePostData> findAllBySuccessAndUploadedAtAfter(final Long userId,
final LocalDateTime time) {
return factory.select(Projections.constructor(SimplePostData.class,
post.id,
post.uploadedAt))
.from(post)
.where(post.userId.eq(userId), post.uploadedAt.after(time), post.state.eq(SUCCESS))
.fetch();
}
}
7 changes: 7 additions & 0 deletions src/main/java/daybyquest/post/query/SimplePostData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package daybyquest.post.query;

import java.time.LocalDateTime;

public record SimplePostData(Long id, LocalDateTime uploadedAt) {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package daybyquest.user.application;

import daybyquest.user.domain.Users;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class CheckUsernameService {

private final Users users;

public CheckUsernameService(final Users users) {
this.users = users;
}

@Transactional(readOnly = true)
public void invoke(final String username) {
users.validateUniqueUsername(username);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package daybyquest.user.application;

import daybyquest.user.domain.User;
import daybyquest.user.domain.Users;
import daybyquest.user.dto.response.UserVisibilityResponse;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class GetVisibilityService {

private final Users users;

public GetVisibilityService(final Users users) {
this.users = users;
}

@Transactional(readOnly = true)
public UserVisibilityResponse invoke(final Long loginId) {
final User user = users.getById(loginId);
return UserVisibilityResponse.of(user);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@

import daybyquest.user.query.Profile;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class MyProfileResponse {

private String username;
private final String username;

private String name;
private final String name;

private String imageIdentifier;
private final String imageIdentifier;

private Long postCount;
private final Long postCount;

private Long followingCount;
private final Long followingCount;

private Long followerCount;
private final Long followerCount;

private MyProfileResponse(final String username, final String name, final String imageIdentifier,
final Long postCount, final Long followingCount, final Long followerCount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@

import java.util.List;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class PageProfilesResponse {

private List<ProfileResponse> users;
private final List<ProfileResponse> users;

private Long lastId;
private final Long lastId;

public PageProfilesResponse(final List<ProfileResponse> users, final Long lastId) {
this.users = users;
Expand Down
14 changes: 6 additions & 8 deletions src/main/java/daybyquest/user/dto/response/ProfileResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,21 @@

import daybyquest.user.query.Profile;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class ProfileResponse {

private String username;
private final String username;

private String name;
private final String name;

private String imageIdentifier;
private final String imageIdentifier;

private Long postCount;
private final Long postCount;

private boolean following;
private final boolean following;

private boolean blocking;
private final boolean blocking;

private ProfileResponse(final String username, final String name, final String imageIdentifier,
final Long postCount,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package daybyquest.user.dto.response;

import daybyquest.user.domain.User;
import lombok.Getter;

@Getter
public class UserVisibilityResponse {

private final String visibility;

private UserVisibilityResponse(final String visibility) {
this.visibility = visibility;
}

public static UserVisibilityResponse of(final User user) {
return new UserVisibilityResponse(user.getVisibility().toString());
}
}
25 changes: 24 additions & 1 deletion src/main/java/daybyquest/user/presentation/UserQueryApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@

import daybyquest.auth.Authorization;
import daybyquest.auth.domain.AccessUser;
import daybyquest.user.application.CheckUsernameService;
import daybyquest.user.application.GetMyProfileService;
import daybyquest.user.application.GetProfileByUsernameService;
import daybyquest.user.application.GetVisibilityService;
import daybyquest.user.dto.response.MyProfileResponse;
import daybyquest.user.dto.response.ProfileResponse;
import daybyquest.user.dto.response.UserVisibilityResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
Expand All @@ -18,10 +21,17 @@ public class UserQueryApi {

private final GetMyProfileService getMyProfileService;

private final CheckUsernameService checkUsernameService;

private final GetVisibilityService getVisibilityService;

public UserQueryApi(final GetProfileByUsernameService getProfileByUsernameService,
final GetMyProfileService getMyProfileService) {
final GetMyProfileService getMyProfileService, final CheckUsernameService checkUsernameService,
final GetVisibilityService getVisibilityService) {
this.getProfileByUsernameService = getProfileByUsernameService;
this.getMyProfileService = getMyProfileService;
this.checkUsernameService = checkUsernameService;
this.getVisibilityService = getVisibilityService;
}

@GetMapping("/profile/{username}")
Expand All @@ -38,4 +48,17 @@ public ResponseEntity<MyProfileResponse> getMyProfile(final AccessUser accessUse
final MyProfileResponse response = getMyProfileService.invoke(accessUser.getId());
return ResponseEntity.ok(response);
}

@GetMapping("/profile/{username}/check")
public ResponseEntity<Void> checkUsername(@PathVariable final String username) {
checkUsernameService.invoke(username);
return ResponseEntity.ok().build();
}

@GetMapping("/profile/visibility")
@Authorization
public ResponseEntity<UserVisibilityResponse> getVisibility(final AccessUser accessUser) {
final UserVisibilityResponse response = getVisibilityService.invoke(accessUser.getId());
return ResponseEntity.ok(response);
}
}
3 changes: 3 additions & 0 deletions src/main/resources/application-web.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ image:
base:
user-identifier: base.png

tracker:
days: 60

spring:
servlet:
multipart:
Expand Down
2 changes: 2 additions & 0 deletions src/main/resources/db/migration/V2__post_date.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE `post`
ADD `uploaded_at` datetime(6);
Loading

0 comments on commit a579d0e

Please sign in to comment.