Merge pull request 'feat: add user statistics functionality with DTOs and service methods' (#46) from feat/user-stats into main
Reviewed-on: #46
This commit is contained in:
commit
890421ec9c
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"java.compile.nullAnalysis.mode": "automatic"
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.magamochi.userinteraction.controller;
|
||||
|
||||
import com.magamochi.common.model.dto.DefaultResponseDTO;
|
||||
import com.magamochi.userinteraction.model.dto.UserStatisticsDTO;
|
||||
import com.magamochi.userinteraction.service.UserStatisticsService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/user/statistics")
|
||||
@CrossOrigin(origins = "*")
|
||||
@RequiredArgsConstructor
|
||||
public class UserStatisticsController {
|
||||
private final UserStatisticsService userStatisticsService;
|
||||
|
||||
@Operation(
|
||||
summary = "Get user statistics",
|
||||
description = "Get statistics for the logged in user.",
|
||||
tags = {"User Statistics"},
|
||||
operationId = "getUserStatistics")
|
||||
@GetMapping
|
||||
public DefaultResponseDTO<UserStatisticsDTO> getUserStatistics() {
|
||||
return DefaultResponseDTO.ok(userStatisticsService.getUserStatistics());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
package com.magamochi.userinteraction.model.dto;
|
||||
|
||||
import java.time.Instant;
|
||||
import lombok.Builder;
|
||||
|
||||
@Builder
|
||||
public record UserRecentActivityDTO(
|
||||
String mangaTitle, String contentTitle, Instant readAt, Long mangaId) {}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.magamochi.userinteraction.model.dto;
|
||||
|
||||
import java.util.List;
|
||||
import lombok.Builder;
|
||||
|
||||
@Builder
|
||||
public record UserStatisticsDTO(
|
||||
long favoriteMangaCount,
|
||||
long mangaReadingCount,
|
||||
long chaptersReadCount,
|
||||
UserRecentActivityDTO lastReadContent,
|
||||
boolean hasReadingActivity,
|
||||
List<UserRecentActivityDTO> recentActivities) {}
|
||||
@ -13,4 +13,6 @@ public interface UserFavoriteMangaRepository extends JpaRepository<UserFavoriteM
|
||||
Optional<UserFavoriteManga> findByUserAndManga(User user, Manga manga);
|
||||
|
||||
Set<UserFavoriteManga> findByUser(User user);
|
||||
|
||||
long countByUser(User user);
|
||||
}
|
||||
|
||||
@ -3,11 +3,25 @@ package com.magamochi.userinteraction.model.repository;
|
||||
import com.magamochi.content.model.entity.MangaContent;
|
||||
import com.magamochi.user.model.entity.User;
|
||||
import com.magamochi.userinteraction.model.entity.UserMangaContentRead;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface UserMangaContentReadRepository extends JpaRepository<UserMangaContentRead, Long> {
|
||||
boolean existsByUserAndMangaContent(User user, MangaContent mangaContent);
|
||||
|
||||
Optional<UserMangaContentRead> findByUserAndMangaContent(User user, MangaContent mangaContent);
|
||||
|
||||
long countByUser(User user);
|
||||
|
||||
@Query(
|
||||
"SELECT COUNT(DISTINCT mcp.manga) FROM UserMangaContentRead umcr "
|
||||
+ "JOIN umcr.mangaContent mc "
|
||||
+ "JOIN mc.mangaContentProvider mcp "
|
||||
+ "WHERE umcr.user = :user")
|
||||
long countDistinctMangaByUser(@Param("user") User user);
|
||||
|
||||
List<UserMangaContentRead> findTop10ByUserOrderByCreatedAtDesc(User user);
|
||||
}
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
package com.magamochi.userinteraction.service;
|
||||
|
||||
import com.magamochi.user.service.UserService;
|
||||
import com.magamochi.userinteraction.model.dto.UserRecentActivityDTO;
|
||||
import com.magamochi.userinteraction.model.dto.UserStatisticsDTO;
|
||||
import com.magamochi.userinteraction.model.entity.UserMangaContentRead;
|
||||
import com.magamochi.userinteraction.model.repository.UserFavoriteMangaRepository;
|
||||
import com.magamochi.userinteraction.model.repository.UserMangaContentReadRepository;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UserStatisticsService {
|
||||
private final UserService userService;
|
||||
private final UserFavoriteMangaRepository userFavoriteMangaRepository;
|
||||
private final UserMangaContentReadRepository userMangaContentReadRepository;
|
||||
|
||||
public UserStatisticsDTO getUserStatistics() {
|
||||
var user = userService.getLoggedUserThrowIfNotFound();
|
||||
|
||||
var favoriteMangaCount = userFavoriteMangaRepository.countByUser(user);
|
||||
var mangaReadingCount = userMangaContentReadRepository.countDistinctMangaByUser(user);
|
||||
var chaptersReadCount = userMangaContentReadRepository.countByUser(user);
|
||||
|
||||
var recentReads = userMangaContentReadRepository.findTop10ByUserOrderByCreatedAtDesc(user);
|
||||
|
||||
UserRecentActivityDTO lastReadContent = null;
|
||||
if (!recentReads.isEmpty()) {
|
||||
lastReadContent = mapToRecentActivityDTO(recentReads.getFirst());
|
||||
}
|
||||
|
||||
var recentActivities =
|
||||
recentReads.stream().map(this::mapToRecentActivityDTO).collect(Collectors.toList());
|
||||
|
||||
return UserStatisticsDTO.builder()
|
||||
.favoriteMangaCount(favoriteMangaCount)
|
||||
.mangaReadingCount(mangaReadingCount)
|
||||
.chaptersReadCount(chaptersReadCount)
|
||||
.lastReadContent(lastReadContent)
|
||||
.hasReadingActivity(!recentReads.isEmpty())
|
||||
.recentActivities(recentActivities)
|
||||
.build();
|
||||
}
|
||||
|
||||
private UserRecentActivityDTO mapToRecentActivityDTO(UserMangaContentRead read) {
|
||||
var mangaContent = read.getMangaContent();
|
||||
var manga = mangaContent.getMangaContentProvider().getManga();
|
||||
|
||||
return UserRecentActivityDTO.builder()
|
||||
.mangaTitle(manga.getTitle())
|
||||
.contentTitle(mangaContent.getTitle())
|
||||
.readAt(read.getCreatedAt())
|
||||
.mangaId(manga.getId())
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user