mirror of
https://github.com/adityachandelgit/BookLore.git
synced 2026-02-18 03:07:40 +01:00
feat(user-stats): add monthly heatmap endpoint
- Add GET /api/v1/user-stats/heatmap/monthly endpoint for month-based data - Keep original /heatmap endpoint unchanged for backward compatibility - Add findSessionCountsByUserAndYearAndMonth repository method - Add getSessionHeatmapForMonth service method
This commit is contained in:
@@ -31,6 +31,20 @@ public class UserStatsController {
|
||||
return ResponseEntity.ok(heatmapData);
|
||||
}
|
||||
|
||||
@Operation(summary = "Get reading session heatmap for a month", description = "Returns daily reading session counts for the authenticated user for a specific year and month")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "Heatmap data retrieved successfully"),
|
||||
@ApiResponse(responseCode = "401", description = "Unauthorized")
|
||||
})
|
||||
@GetMapping("/heatmap/monthly")
|
||||
@PreAuthorize("@securityUtil.canAccessUserStats() or @securityUtil.isAdmin()")
|
||||
public ResponseEntity<List<ReadingSessionHeatmapResponse>> getHeatmapForMonth(
|
||||
@RequestParam int year,
|
||||
@RequestParam int month) {
|
||||
List<ReadingSessionHeatmapResponse> heatmapData = readingSessionService.getSessionHeatmapForMonth(year, month);
|
||||
return ResponseEntity.ok(heatmapData);
|
||||
}
|
||||
|
||||
@Operation(summary = "Get reading session timeline for a week", description = "Returns reading sessions grouped by book for calendar timeline view")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "Timeline data retrieved successfully"),
|
||||
@@ -109,4 +123,16 @@ public class UserStatsController {
|
||||
List<CompletionTimelineResponse> timeline = readingSessionService.getCompletionTimeline(year);
|
||||
return ResponseEntity.ok(timeline);
|
||||
}
|
||||
|
||||
@Operation(summary = "Get book completion heatmap", description = "Returns monthly book completion counts for the last 10 years for the authenticated user")
|
||||
@ApiResponses({
|
||||
@ApiResponse(responseCode = "200", description = "Book completion heatmap data retrieved successfully"),
|
||||
@ApiResponse(responseCode = "401", description = "Unauthorized")
|
||||
})
|
||||
@GetMapping("/book-completion-heatmap")
|
||||
@PreAuthorize("@securityUtil.canAccessUserStats() or @securityUtil.isAdmin()")
|
||||
public ResponseEntity<List<BookCompletionHeatmapResponse>> getBookCompletionHeatmap() {
|
||||
List<BookCompletionHeatmapResponse> heatmapData = readingSessionService.getBookCompletionHeatmap();
|
||||
return ResponseEntity.ok(heatmapData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,20 @@ public interface ReadingSessionRepository extends JpaRepository<ReadingSessionEn
|
||||
""")
|
||||
List<ReadingSessionCountDto> findSessionCountsByUserAndYear(@Param("userId") Long userId, @Param("year") int year);
|
||||
|
||||
@Query("""
|
||||
SELECT CAST(rs.startTime AS LocalDate) as date, COUNT(rs) as count
|
||||
FROM ReadingSessionEntity rs
|
||||
WHERE rs.user.id = :userId
|
||||
AND YEAR(rs.startTime) = :year
|
||||
AND MONTH(rs.startTime) = :month
|
||||
GROUP BY CAST(rs.startTime AS LocalDate)
|
||||
ORDER BY date
|
||||
""")
|
||||
List<ReadingSessionCountDto> findSessionCountsByUserAndYearAndMonth(
|
||||
@Param("userId") Long userId,
|
||||
@Param("year") int year,
|
||||
@Param("month") int month);
|
||||
|
||||
@Query("""
|
||||
SELECT
|
||||
b.id as bookId,
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.adityachandel.booklore.config.security.service.AuthenticationService;
|
||||
import com.adityachandel.booklore.exception.ApiError;
|
||||
import com.adityachandel.booklore.model.dto.BookLoreUser;
|
||||
import com.adityachandel.booklore.model.dto.request.ReadingSessionRequest;
|
||||
import com.adityachandel.booklore.model.dto.response.BookCompletionHeatmapResponse;
|
||||
import com.adityachandel.booklore.model.dto.response.CompletionTimelineResponse;
|
||||
import com.adityachandel.booklore.model.dto.response.FavoriteReadingDaysResponse;
|
||||
import com.adityachandel.booklore.model.dto.response.GenreStatisticsResponse;
|
||||
@@ -94,6 +95,20 @@ public class ReadingSessionService {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<ReadingSessionHeatmapResponse> getSessionHeatmapForMonth(int year, int month) {
|
||||
BookLoreUser authenticatedUser = authenticationService.getAuthenticatedUser();
|
||||
Long userId = authenticatedUser.getId();
|
||||
|
||||
return readingSessionRepository.findSessionCountsByUserAndYearAndMonth(userId, year, month)
|
||||
.stream()
|
||||
.map(dto -> ReadingSessionHeatmapResponse.builder()
|
||||
.date(dto.getDate())
|
||||
.count(dto.getCount())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<ReadingSessionTimelineResponse> getSessionTimelineForWeek(int year, int week) {
|
||||
BookLoreUser authenticatedUser = authenticationService.getAuthenticatedUser();
|
||||
@@ -254,4 +269,22 @@ public class ReadingSessionService {
|
||||
.createdAt(session.getCreatedAt())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public List<BookCompletionHeatmapResponse> getBookCompletionHeatmap() {
|
||||
BookLoreUser authenticatedUser = authenticationService.getAuthenticatedUser();
|
||||
Long userId = authenticatedUser.getId();
|
||||
|
||||
int currentYear = LocalDate.now().getYear();
|
||||
int startYear = currentYear - 9;
|
||||
|
||||
return userBookProgressRepository.findBookCompletionHeatmap(userId, startYear, currentYear)
|
||||
.stream()
|
||||
.map(dto -> BookCompletionHeatmapResponse.builder()
|
||||
.year(dto.getYear())
|
||||
.month(dto.getMonth())
|
||||
.count(dto.getCount())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user