Added late read module

This commit is contained in:
aditya.chandel
2024-12-13 15:42:14 -07:00
parent baff376b9c
commit 1e9249b257
20 changed files with 346 additions and 69 deletions

View File

@@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Random;
@RequestMapping("/v1/book")
@RestController
@@ -30,9 +31,13 @@ public class BookController {
return ResponseEntity.ok(booksService.getBook(bookId));
}
@GetMapping()
public ResponseEntity<Page<BookDTO>> getBooks(@RequestParam(defaultValue = "0") @Min(0) int page, @RequestParam(defaultValue = "25") @Min(1) @Max(100) int size) {
Page<BookDTO> books = booksService.getBooks(page, size);
@GetMapping
public ResponseEntity<Page<BookDTO>> getBooks(
@RequestParam(defaultValue = "0") @Min(0) int page,
@RequestParam(defaultValue = "25") @Min(1) @Max(100) int size,
@RequestParam(defaultValue = "lastReadTime") String sortBy,
@RequestParam(defaultValue = "desc") String sortDir) {
Page<BookDTO> books = booksService.getBooks(page, size, sortBy, sortDir);
return ResponseEntity.ok(books);
}
@@ -44,6 +49,14 @@ public class BookController {
@GetMapping("/{bookId}/cover")
public ResponseEntity<Resource> getBookCover(@PathVariable long bookId) {
Random random = new Random();
int delay = 250 + random.nextInt(750);
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
return ResponseEntity.ok(booksService.getBookCover(bookId));
}
@@ -52,9 +65,20 @@ public class BookController {
return booksService.getBookData(bookId);
}
@GetMapping("/{bookId}/viewer-setting")
public ResponseEntity<BookViewerSettingDTO> getBookViewerSettings(@PathVariable long bookId) {
return ResponseEntity.ok(booksService.getBookViewerSetting(bookId));
}
@PutMapping("/{bookId}/viewer-setting")
public ResponseEntity<Void> updateBookViewerSettings(@RequestBody BookViewerSettingDTO bookViewerSettingDTO, @PathVariable long bookId) {
booksService.saveBookViewerSetting(bookId, bookViewerSettingDTO);
return ResponseEntity.noContent().build();
}
@PutMapping("/{bookId}/update-last-read")
public ResponseEntity<Void> updateBookViewerSettings(@PathVariable long bookId) {
booksService.updateLastReadTime(bookId);
return ResponseEntity.noContent().build();
}
}

View File

@@ -3,6 +3,7 @@ package com.adityachandel.booklore.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@@ -13,5 +14,6 @@ public class BookDTO {
private Long libraryId;
private String fileName;
private String title;
private Instant lastReadTime;
private List<AuthorDTO> authors = new ArrayList<>();
}

View File

@@ -3,6 +3,7 @@ package com.adityachandel.booklore.entity;
import jakarta.persistence.*;
import lombok.*;
import java.time.Instant;
import java.util.List;
@Entity
@@ -40,4 +41,7 @@ public class Book {
@OneToOne(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true)
private BookViewerSetting viewerSetting;
@Column(name = "last_read_time")
private Instant lastReadTime;
}

View File

@@ -19,5 +19,7 @@ public interface BookRepository extends JpaRepository<Book, Long>, JpaSpecificat
Optional<Book> findBookByIdAndLibraryId(long id, long libraryId);
List<Book> findByTitleContainingIgnoreCase(String title);
Page<Book> findByLastReadTimeIsNotNull(Pageable pageable);
}

View File

@@ -10,6 +10,7 @@ import com.adityachandel.booklore.exception.ErrorCode;
import com.adityachandel.booklore.repository.BookRepository;
import com.adityachandel.booklore.repository.BookViewerSettingRepository;
import com.adityachandel.booklore.service.parser.PdfParser;
import com.adityachandel.booklore.transformer.BookSettingTransformer;
import com.adityachandel.booklore.transformer.BookTransformer;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -18,6 +19,7 @@ import org.springframework.core.io.UrlResource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
@@ -28,6 +30,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -49,10 +52,13 @@ public class BooksService {
return BookTransformer.convertToBookDTO(book);
}
public Page<BookDTO> getBooks(int page, int size) {
PageRequest pageRequest = PageRequest.of(page, size);
Page<Book> bookPage = bookRepository.findAll(PageRequest.of(page, size));
List<BookDTO> bookDTOs = bookPage.getContent().stream().map(BookTransformer::convertToBookDTO).collect(Collectors.toList());
public Page<BookDTO> getBooks(int page, int size, String sortBy, String sortDir) {
Sort sort = Sort.by(Sort.Direction.fromString(sortDir), sortBy);
PageRequest pageRequest = PageRequest.of(page, size, sort);
Page<Book> bookPage = bookRepository.findByLastReadTimeIsNotNull(pageRequest);
List<BookDTO> bookDTOs = bookPage.getContent().stream()
.map(BookTransformer::convertToBookDTO)
.collect(Collectors.toList());
return new PageImpl<>(bookDTOs, pageRequest, bookPage.getTotalElements());
}
@@ -102,10 +108,6 @@ public class BooksService {
Book book = pdfParser.parseBook(filePath.toAbsolutePath().toString(), appProperties.getPathConfig());
book.setViewerSetting(BookViewerSetting.builder()
.bookId(book.getId())
.pageNumber(0)
.zoom("page-fit")
.spread("off")
.sidebar_visible(false)
.build());
return book;
}
@@ -147,4 +149,15 @@ public class BooksService {
List<Book> books = bookRepository.findByTitleContainingIgnoreCase(title);
return books.stream().map(BookTransformer::convertToBookDTO).toList();
}
public BookViewerSettingDTO getBookViewerSetting(long bookId) {
BookViewerSetting bookViewerSetting = bookViewerSettingRepository.findById(bookId).orElseThrow(() -> ErrorCode.BOOK_NOT_FOUND.createException(bookId));
return BookSettingTransformer.convertToDTO(bookViewerSetting);
}
public void updateLastReadTime(long bookId) {
Book book = bookRepository.findById(bookId).orElseThrow(() -> ErrorCode.BOOK_NOT_FOUND.createException(bookId));
book.setLastReadTime(Instant.now());
bookRepository.save(book);
}
}

View File

@@ -0,0 +1,16 @@
package com.adityachandel.booklore.transformer;
import com.adityachandel.booklore.dto.BookViewerSettingDTO;
import com.adityachandel.booklore.entity.BookViewerSetting;
public class BookSettingTransformer {
public static BookViewerSettingDTO convertToDTO(BookViewerSetting bookViewerSetting) {
return BookViewerSettingDTO.builder()
.zoom(bookViewerSetting.getZoom())
.pageNumber(bookViewerSetting.getPageNumber())
.spread(bookViewerSetting.getSpread())
.sidebar_visible(bookViewerSetting.isSidebar_visible())
.build();
}
}

View File

@@ -13,6 +13,7 @@ public class BookTransformer {
bookDTO.setLibraryId(book.getLibrary().getId());
bookDTO.setFileName(book.getFileName());
bookDTO.setTitle(book.getTitle());
bookDTO.setLastReadTime(book.getLastReadTime());
bookDTO.setAuthors(book.getAuthors().stream().map(AuthorTransformer::toAuthorDTO).collect(Collectors.toList()));
return bookDTO;
}

View File

@@ -7,13 +7,16 @@ CREATE TABLE IF NOT EXISTS library
CREATE TABLE IF NOT EXISTS book
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255),
file_name VARCHAR(255) NOT NULL,
library_id BIGINT NOT NULL,
path VARCHAR(1000) NOT NULL,
id BIGINT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255),
file_name VARCHAR(255) NOT NULL,
library_id BIGINT NOT NULL,
path VARCHAR(1000) NOT NULL,
last_read_time TIMESTAMP NULL,
CONSTRAINT fk_library FOREIGN KEY (library_id) REFERENCES library (id) ON DELETE CASCADE,
CONSTRAINT unique_file_library UNIQUE (file_name, library_id)
CONSTRAINT unique_file_library UNIQUE (file_name, library_id),
INDEX idx_library_id (library_id),
INDEX idx_last_read_time (last_read_time)
);
CREATE TABLE IF NOT EXISTS author
@@ -29,15 +32,17 @@ CREATE TABLE IF NOT EXISTS book_author_mapping
author_id BIGINT NOT NULL,
CONSTRAINT fk_book_author_mapping_book FOREIGN KEY (book_id) REFERENCES book (id) ON DELETE CASCADE,
CONSTRAINT fk_book_author_mapping_author FOREIGN KEY (author_id) REFERENCES author (id),
CONSTRAINT unique_book_author UNIQUE (book_id, author_id)
CONSTRAINT unique_book_author UNIQUE (book_id, author_id),
INDEX idx_book_id (book_id),
INDEX idx_author_id (author_id)
);
CREATE TABLE IF NOT EXISTS book_viewer_setting
(
book_id BIGINT PRIMARY KEY,
page_number INT DEFAULT 1,
zoom VARCHAR(32) DEFAULT 'page-fit',
zoom VARCHAR(16) DEFAULT 'page-fit',
sidebar_visible BOOLEAN DEFAULT false,
spread VARCHAR(32) DEFAULT 'off',
spread VARCHAR(16) DEFAULT 'odd',
CONSTRAINT fk_book_viewer_setting FOREIGN KEY (book_id) REFERENCES book (id) ON DELETE CASCADE
);