Skip to content

Commit 7980386

Browse files
authored
Create HTTP.GET Bookmarks pagination endpoint #294 (#311)
* Add HTTP.GET Bookmarks pagination endpoint [In progress] #294 * Implement `listPaginatedJDBC()` method in `BookmarkService`[In progress] #294 * Extend `PagingAndSorting` interface [In progress] #294 * Add `PaginatedBookmarkRes` record [In progress] #294 * Add `PaginatedBookmarkReq` record [In progress] #294 * Extend `PagingAndSortingRepository` [Waiting Review] #294 * Create and implement `PageGreaterThanTotalException` [Waiting Review] #294 * Add paginationURI and expected bkmk titles [Waiting Review] #294 * Add HTTP.GET Bookmark pagination tests [Waiting Review] #294 * Add more bookmarks to jsmith for pagination tests [Waiting Review] #294
1 parent 35f16e1 commit 7980386

8 files changed

Lines changed: 358 additions & 19 deletions

File tree

server/src/main/java/dev/findfirst/core/controller/BookmarkController.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@
1111
import jakarta.validation.constraints.NotNull;
1212
import jakarta.validation.constraints.Size;
1313

14-
import dev.findfirst.core.dto.AddBkmkReq;
15-
import dev.findfirst.core.dto.BookmarkDTO;
16-
import dev.findfirst.core.dto.TagDTO;
17-
import dev.findfirst.core.dto.UpdateBookmarkReq;
14+
import dev.findfirst.core.dto.*;
1815
import dev.findfirst.core.exceptions.BookmarkNotFoundException;
16+
import dev.findfirst.core.exceptions.PageGreaterThanTotalException;
1917
import dev.findfirst.core.exceptions.TagNotFoundException;
2018
import dev.findfirst.core.model.jdbc.BookmarkTag;
2119
import dev.findfirst.core.service.BookmarkService;
@@ -58,6 +56,12 @@ public ResponseEntity<List<BookmarkDTO>> getAllBookmarks() {
5856
return new Response<>(bookmarkService.listJDBC(), HttpStatus.OK).get();
5957
}
6058

59+
@GetMapping("/paginated/bookmarks")
60+
public ResponseEntity<PaginatedBookmarkRes> getPaginatedBookmarks(@Valid PaginatedBookmarkReq req)
61+
throws PageGreaterThanTotalException {
62+
return new Response<>(bookmarkService.listPaginatedJDBC(req), HttpStatus.OK).get();
63+
}
64+
6165
@GetMapping(value = "/bookmarks/export", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
6266
public ResponseEntity<byte[]> exportAllBookmarks() {
6367
return ResponseEntity.ok()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package dev.findfirst.core.dto;
2+
3+
import jakarta.validation.constraints.Max;
4+
import jakarta.validation.constraints.Min;
5+
6+
public record PaginatedBookmarkReq(
7+
@Min(1) Integer page,
8+
@Min(6) @Max(25) Integer size
9+
) {
10+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package dev.findfirst.core.dto;
2+
3+
import java.util.List;
4+
5+
public record PaginatedBookmarkRes(List<BookmarkDTO> bookmarks, Integer totalPages, Integer currentPage) {
6+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package dev.findfirst.core.exceptions;
2+
3+
import org.springframework.http.HttpStatus;
4+
5+
public class PageGreaterThanTotalException extends ErrorResponseException {
6+
public PageGreaterThanTotalException(int page) {
7+
super(HttpStatus.BAD_REQUEST, "Page parameter greater than total pages",
8+
"Requested page " + page + " exceeds total pages.");
9+
}
10+
}

server/src/main/java/dev/findfirst/core/repository/jdbc/BookmarkJDBCRepository.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,24 @@
55

66
import dev.findfirst.core.model.jdbc.BookmarkJDBC;
77

8+
import org.springframework.data.domain.Page;
9+
import org.springframework.data.domain.Pageable;
810
import org.springframework.data.jdbc.repository.query.Query;
911
import org.springframework.data.repository.CrudRepository;
12+
import org.springframework.data.repository.PagingAndSortingRepository;
1013
import org.springframework.data.repository.query.Param;
1114

12-
public interface BookmarkJDBCRepository extends CrudRepository<BookmarkJDBC, Long> {
15+
public interface BookmarkJDBCRepository
16+
extends CrudRepository<BookmarkJDBC, Long>, PagingAndSortingRepository<BookmarkJDBC, Long> {
1317

1418
@Query("SELECT * FROM bookmark where bookmark.url = :url AND bookmark.user_id = :userID")
1519
public Optional<BookmarkJDBC> findByUrl(@Param("url") String url, @Param("userID") int userID);
1620

1721
@Query("SELECT * FROM bookmark where bookmark.user_id = :userID")
1822
public List<BookmarkJDBC> findAllBookmarksByUser(@Param("userID") int userID);
1923

24+
public Page<BookmarkJDBC> findAllByUserId(int userId, Pageable pageable);
25+
2026

2127
@Query("SELECT b FROM Bookmark b WHERE b.screenshotUrl IS NULL OR TRIM(b.screenshotUrl)=''")
2228
List<BookmarkJDBC> findBookmarksWithEmptyOrBlankScreenShotUrl();

server/src/main/java/dev/findfirst/core/service/BookmarkService.java

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,10 @@
1414
import java.util.Map;
1515
import java.util.Optional;
1616

17-
import dev.findfirst.core.dto.AddBkmkReq;
18-
import dev.findfirst.core.dto.BookmarkDTO;
19-
import dev.findfirst.core.dto.BookmarkOnly;
20-
import dev.findfirst.core.dto.TagDTO;
21-
import dev.findfirst.core.dto.TagOnly;
22-
import dev.findfirst.core.dto.UpdateBookmarkReq;
17+
import dev.findfirst.core.dto.*;
2318
import dev.findfirst.core.exceptions.BookmarkAlreadyExistsException;
2419
import dev.findfirst.core.exceptions.BookmarkNotFoundException;
20+
import dev.findfirst.core.exceptions.PageGreaterThanTotalException;
2521
import dev.findfirst.core.exceptions.TagNotFoundException;
2622
import dev.findfirst.core.model.ExportBookmark;
2723
import dev.findfirst.core.model.TagBookmarks;
@@ -37,6 +33,8 @@
3733
import lombok.extern.slf4j.Slf4j;
3834
import org.jsoup.Jsoup;
3935
import org.jsoup.nodes.Document;
36+
import org.springframework.data.domain.Page;
37+
import org.springframework.data.domain.Pageable;
4038
import org.springframework.scheduling.annotation.Scheduled;
4139
import org.springframework.security.core.context.SecurityContextHolder;
4240
import org.springframework.stereotype.Service;
@@ -67,6 +65,28 @@ public List<BookmarkDTO> listJDBC() {
6765
bookmarkJDBCRepository.findAllBookmarksByUser(uContext.getUserId()), uContext.getUserId());
6866
}
6967

68+
public PaginatedBookmarkRes listPaginatedJDBC(PaginatedBookmarkReq reqBkmk)
69+
throws PageGreaterThanTotalException {
70+
// Page is 0 indexed.
71+
int page = reqBkmk.page() - 1;
72+
73+
Pageable pageable = Pageable.ofSize(reqBkmk.size()).withPage(page);
74+
75+
Page<BookmarkJDBC> pageResult =
76+
bookmarkJDBCRepository.findAllByUserId(uContext.getUserId(), pageable);
77+
List<BookmarkJDBC> pageContent = pageResult.getContent();
78+
Integer totalPages = pageResult.getTotalPages();
79+
80+
if (pageContent.isEmpty() && page > 0)
81+
throw new PageGreaterThanTotalException(page + 1);
82+
83+
List<BookmarkDTO> bookmarks = convertBookmarkJDBCToDTO(pageContent, uContext.getUserId());
84+
85+
return new PaginatedBookmarkRes(bookmarks, totalPages, reqBkmk.page());
86+
87+
88+
}
89+
7090
public Optional<BookmarkDTO> getBookmarkById(long id) {
7191
var bkOpt = bookmarkJDBCRepository.findById(id);
7292

server/src/main/resources/db/dev/V1.0.9__test_data_db_revamp.sql

Lines changed: 212 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,223 @@ values
3535
true
3636
);
3737

38-
-- king's bookmark
3938
-- id: 4
39+
insert into
40+
bookmark (id, title, url, user_id, scrapable)
41+
values
42+
(
43+
4,
44+
'Best Cheesecake Recipe2',
45+
'https://sugarspunrun.com/best-cheesecake-recipe/',
46+
1,
47+
true
48+
);
49+
50+
-- id: 5
51+
insert into
52+
bookmark (id, title, url, user_id, scrapable)
53+
values
54+
(
55+
5,
56+
'Best Cheesecake Recipe3',
57+
'https://sugarspunrun.com/best-cheesecake-recipe/',
58+
1,
59+
true
60+
);
61+
62+
-- id: 6
63+
insert into
64+
bookmark (id, title, url, user_id, scrapable)
65+
values
66+
(
67+
6,
68+
'Best Cheesecake Recipe4',
69+
'https://sugarspunrun.com/best-cheesecake-recipe/',
70+
1,
71+
true
72+
);
73+
74+
-- id: 7
75+
insert into
76+
bookmark (id, title, url, user_id, scrapable)
77+
values
78+
(
79+
7,
80+
'Best Cheesecake Recipe5',
81+
'https://sugarspunrun.com/best-cheesecake-recipe/',
82+
1,
83+
true
84+
);
85+
86+
-- id: 8
87+
insert into
88+
bookmark (id, title, url, user_id, scrapable)
89+
values
90+
(
91+
8,
92+
'Best Cheesecake Recipe6',
93+
'https://sugarspunrun.com/best-cheesecake-recipe/',
94+
1,
95+
true
96+
);
97+
98+
-- id: 9
99+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
100+
VALUES (
101+
9,
102+
'Ultimate Chocolate Cake',
103+
'https://sallysbakingaddiction.com/triple-chocolate-layer-cake/',
104+
1,
105+
true
106+
);
107+
108+
-- id: 10
109+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
110+
VALUES (
111+
10,
112+
'Top 10 Travel Destinations',
113+
'https://www.lonelyplanet.com/articles/top-travel-destinations',
114+
1,
115+
true
116+
);
117+
118+
-- id: 11
119+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
120+
VALUES (
121+
11,
122+
'Effective Java Programming',
123+
'https://www.oreilly.com/library/view/effective-java-3rd/',
124+
1,
125+
true
126+
);
127+
128+
-- id: 12
129+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
130+
VALUES (
131+
12,
132+
'Healthy Meal Plans',
133+
'https://www.eatingwell.com/category/4286/meal-plans/',
134+
1,
135+
true
136+
);
137+
138+
-- id: 13
139+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
140+
VALUES (
141+
13,
142+
'Best Running Shoes 2024',
143+
'https://www.runnersworld.com/gear/a20865505/best-running-shoes/',
144+
1,
145+
true
146+
);
147+
148+
-- id: 14
149+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
150+
VALUES (
151+
14,
152+
'Beginner’s Guide to Investing',
153+
'https://www.investopedia.com/investing-4427765',
154+
1,
155+
true
156+
);
157+
158+
-- id: 15
159+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
160+
VALUES (
161+
15,
162+
'How to Brew the Perfect Coffee',
163+
'https://www.javapresse.com/blogs/buying-coffee/how-to-make-coffee',
164+
1,
165+
true
166+
);
167+
168+
-- id: 16
169+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
170+
VALUES (
171+
16,
172+
'Essential Hiking Gear',
173+
'https://www.rei.com/learn/expert-advice/day-hiking-checklist.html',
174+
1,
175+
true
176+
);
177+
178+
-- id: 17
179+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
180+
VALUES (
181+
17,
182+
'Mastering React',
183+
'https://react.dev/learn',
184+
1,
185+
true
186+
);
187+
188+
-- id: 18
189+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
190+
VALUES (
191+
18,
192+
'Top 5 Budget Travel Tips',
193+
'https://www.nomadicmatt.com/travel-tips/',
194+
1,
195+
true
196+
);
197+
198+
-- id: 19
199+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
200+
VALUES (
201+
19,
202+
'Home Workout Routines',
203+
'https://www.nerdfitness.com/blog/beginner-bodyweight-workout/',
204+
1,
205+
true
206+
);
207+
208+
-- id: 20
209+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
210+
VALUES (
211+
20,
212+
'Best Sci-Fi Books of All Time',
213+
'https://www.penguinrandomhouse.com/the-best-sci-fi-books-of-all-time',
214+
1,
215+
true
216+
);
217+
218+
-- id: 21
219+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
220+
VALUES (
221+
21,
222+
'Understanding Stock Markets',
223+
'https://www.wallstreetmojo.com/stock-market-basics/',
224+
1,
225+
true
226+
);
227+
228+
-- id: 22
229+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
230+
VALUES (
231+
22,
232+
'Gourmet Pizza Recipes',
233+
'https://www.bonappetit.com/gallery/pizza-recipes',
234+
1,
235+
true
236+
);
237+
238+
-- id: 23
239+
INSERT INTO bookmark (id, title, url, user_id, scrapable)
240+
VALUES (
241+
23,
242+
'The Best Coding Practices',
243+
'https://stackify.com/top-20-coding-best-practices/',
244+
1,
245+
true
246+
);
247+
248+
-- king's bookmark
249+
-- id: 24
40250
insert into
41251
bookmark (id, title, url, user_id, scrapable)
42252
values
43253
(
44-
4,
254+
24,
45255
'Favorite Chicken Parm',
46256
'https://www.foodnetwork.com/recipes/bobby-flay/chicken-parmigiana-recipe-1952359',
47257
2,

0 commit comments

Comments
 (0)