nandi/gleanpublic Fork 0
a934412
Commits
Clone
git clone https://git.rickub.com/nandi/glean.git
git clone ssh://git@rickub.com/nandi/glean.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Fix pagination on unread and read pageUnverified

Julien Robert committed 2026-05-18T12:30:21+02:00 Browse files
a934412 parent: 9755234
modified internal/db/article.go +13 -1
@@ -421,7 +421,7 @@ func (s *ArticleStore) CountNewArticles(ctx context.Context, userDID string, sin
421421 return count, err
422422 }
423423
424-func (s *ArticleStore) GetNextArticleID(ctx context.Context, userDID string, articleID int64, feedURL string, liked bool) (*int64, error) {
424+func (s *ArticleStore) GetNextArticleID(ctx context.Context, userDID string, articleID int64, feedURL string, liked bool, status string) (*int64, error) {
425425 var fromParts []string
426426 var whereParts []string
427427
@@ -437,6 +437,15 @@ func (s *ArticleStore) GetNextArticleID(ctx context.Context, userDID string, art
437437 fromParts = append(fromParts, "JOIN articles.likes l ON l.author_did = ? AND l.article_url = a.url")
438438 }
439439
440+ switch status {
441+ case "unread":
442+ fromParts = append(fromParts, "LEFT JOIN articles.read_state rs ON rs.user_did = ? AND rs.article_id = a.id")
443+ whereParts = append(whereParts, "(rs.is_read = 0 OR rs.is_read IS NULL)")
444+ case "read":
445+ fromParts = append(fromParts, "JOIN articles.read_state rs ON rs.user_did = ? AND rs.article_id = a.id")
446+ whereParts = append(whereParts, "rs.is_read = 1")
447+ }
448+
440449 whereParts = append(whereParts, "a.id != ?")
441450
442451 fromClause := strings.Join(fromParts, " ")
@@ -464,6 +473,9 @@ func (s *ArticleStore) GetNextArticleID(ctx context.Context, userDID string, art
464473 if liked {
465474 args = append(args, userDID)
466475 }
476+ if status == "unread" || status == "read" {
477+ args = append(args, userDID)
478+ }
467479 args = append(args, articleID, articleID)
468480
469481 var next sql.NullInt64
@@ -421,7 +421,7 @@ func (s *ArticleStore) CountNewArticles(ctx context.Context, userDID string, sin
421 return count, err421 return count, err
422 }422 }
423 423
424-func (s *ArticleStore) GetNextArticleID(ctx context.Context, userDID string, articleID int64, feedURL string, liked bool) (*int64, error) {424+func (s *ArticleStore) GetNextArticleID(ctx context.Context, userDID string, articleID int64, feedURL string, liked bool, status string) (*int64, error) {
425 var fromParts []string425 var fromParts []string
426 var whereParts []string426 var whereParts []string
427 427
@@ -437,6 +437,15 @@ func (s *ArticleStore) GetNextArticleID(ctx context.Context, userDID string, art
437 fromParts = append(fromParts, "JOIN articles.likes l ON l.author_did = ? AND l.article_url = a.url")437 fromParts = append(fromParts, "JOIN articles.likes l ON l.author_did = ? AND l.article_url = a.url")
438 }438 }
439 439
440+ switch status {
441+ case "unread":
442+ fromParts = append(fromParts, "LEFT JOIN articles.read_state rs ON rs.user_did = ? AND rs.article_id = a.id")
443+ whereParts = append(whereParts, "(rs.is_read = 0 OR rs.is_read IS NULL)")
444+ case "read":
445+ fromParts = append(fromParts, "JOIN articles.read_state rs ON rs.user_did = ? AND rs.article_id = a.id")
446+ whereParts = append(whereParts, "rs.is_read = 1")
447+ }
448+
440 whereParts = append(whereParts, "a.id != ?")449 whereParts = append(whereParts, "a.id != ?")
441 450
442 fromClause := strings.Join(fromParts, " ")451 fromClause := strings.Join(fromParts, " ")
@@ -464,6 +473,9 @@ func (s *ArticleStore) GetNextArticleID(ctx context.Context, userDID string, art
464 if liked {473 if liked {
465 args = append(args, userDID)474 args = append(args, userDID)
466 }475 }
476+ if status == "unread" || status == "read" {
477+ args = append(args, userDID)
478+ }
467 args = append(args, articleID, articleID)479 args = append(args, articleID, articleID)
468 480
469 var next sql.NullInt64481 var next sql.NullInt64
modified internal/server/annotations_handler.go +1 -1
@@ -57,7 +57,7 @@ func (s *Server) handleLibrary(w http.ResponseWriter, r *http.Request) {
5757 likedPage.HasNext = true
5858 likedPage.NextPage = likedPage.Page + 1
5959 }
60- navSuffix := buildNavSuffix("", true)
60+ navSuffix := buildNavSuffix("", true, "")
6161 for _, a := range articles {
6262 a.NavSuffix = navSuffix
6363 }
@@ -57,7 +57,7 @@ func (s *Server) handleLibrary(w http.ResponseWriter, r *http.Request) {
57 likedPage.HasNext = true57 likedPage.HasNext = true
58 likedPage.NextPage = likedPage.Page + 158 likedPage.NextPage = likedPage.Page + 1
59 }59 }
60- navSuffix := buildNavSuffix("", true)60+ navSuffix := buildNavSuffix("", true, "")
61 for _, a := range articles {61 for _, a := range articles {
62 a.NavSuffix = navSuffix62 a.NavSuffix = navSuffix
63 }63 }
modified internal/server/articles_handler.go +8 -4
@@ -89,7 +89,7 @@ func (s *Server) handleArticles(w http.ResponseWriter, r *http.Request) {
8989 articles = articles[:page.PageSize]
9090 }
9191
92- navSuffix := buildNavSuffix(feedURL, false)
92+ navSuffix := buildNavSuffix(feedURL, false, status)
9393 for _, a := range articles {
9494 a.NavSuffix = navSuffix
9595 }
@@ -192,6 +192,7 @@ func (s *Server) handleArticleDetail(w http.ResponseWriter, r *http.Request) {
192192
193193 fromFeedURL := r.URL.Query().Get("from_feed")
194194 navLiked := r.URL.Query().Get("liked") == "1"
195+ navStatus := r.URL.Query().Get("status")
195196
196197 g, gCtx := errgroup.WithContext(ctx)
197198
@@ -255,7 +256,7 @@ func (s *Server) handleArticleDetail(w http.ResponseWriter, r *http.Request) {
255256
256257 g.Go(func() error {
257258 var err error
258- nextID, err = s.dbs.Articles.GetNextArticleID(gCtx, user.DID, id, fromFeedURL, navLiked)
259+ nextID, err = s.dbs.Articles.GetNextArticleID(gCtx, user.DID, id, fromFeedURL, navLiked, navStatus)
259260 if err != nil {
260261 s.logger.Warn("failed to get next article", "error", err, "id", id)
261262 }
@@ -276,7 +277,7 @@ func (s *Server) handleArticleDetail(w http.ResponseWriter, r *http.Request) {
276277 "HasLiked": liked,
277278 "Annotations": annotations,
278279 "NextID": nextID,
279- "NextSuffix": buildNavSuffix(fromFeedURL, navLiked),
280+ "NextSuffix": buildNavSuffix(fromFeedURL, navLiked, navStatus),
280281 })
281282 }
282283
@@ -478,7 +479,7 @@ func (s *Server) handleFetchContent(w http.ResponseWriter, r *http.Request) {
478479 s.logger.Info("scraped article content", "id", id, "url", article.URL.String, "content_len", len(cleaned))
479480 }
480481
481-func buildNavSuffix(feedURL string, liked bool) string {
482+func buildNavSuffix(feedURL string, liked bool, status string) string {
482483 v := url.Values{}
483484 if feedURL != "" {
484485 v.Set("from_feed", feedURL)
@@ -486,6 +487,9 @@ func buildNavSuffix(feedURL string, liked bool) string {
486487 if liked {
487488 v.Set("liked", "1")
488489 }
490+ if status != "" {
491+ v.Set("status", status)
492+ }
489493 if len(v) == 0 {
490494 return ""
491495 }
@@ -89,7 +89,7 @@ func (s *Server) handleArticles(w http.ResponseWriter, r *http.Request) {
89 articles = articles[:page.PageSize]89 articles = articles[:page.PageSize]
90 }90 }
91 91
92- navSuffix := buildNavSuffix(feedURL, false)92+ navSuffix := buildNavSuffix(feedURL, false, status)
93 for _, a := range articles {93 for _, a := range articles {
94 a.NavSuffix = navSuffix94 a.NavSuffix = navSuffix
95 }95 }
@@ -192,6 +192,7 @@ func (s *Server) handleArticleDetail(w http.ResponseWriter, r *http.Request) {
192 192
193 fromFeedURL := r.URL.Query().Get("from_feed")193 fromFeedURL := r.URL.Query().Get("from_feed")
194 navLiked := r.URL.Query().Get("liked") == "1"194 navLiked := r.URL.Query().Get("liked") == "1"
195+ navStatus := r.URL.Query().Get("status")
195 196
196 g, gCtx := errgroup.WithContext(ctx)197 g, gCtx := errgroup.WithContext(ctx)
197 198
@@ -255,7 +256,7 @@ func (s *Server) handleArticleDetail(w http.ResponseWriter, r *http.Request) {
255 256
256 g.Go(func() error {257 g.Go(func() error {
257 var err error258 var err error
258- nextID, err = s.dbs.Articles.GetNextArticleID(gCtx, user.DID, id, fromFeedURL, navLiked)259+ nextID, err = s.dbs.Articles.GetNextArticleID(gCtx, user.DID, id, fromFeedURL, navLiked, navStatus)
259 if err != nil {260 if err != nil {
260 s.logger.Warn("failed to get next article", "error", err, "id", id)261 s.logger.Warn("failed to get next article", "error", err, "id", id)
261 }262 }
@@ -276,7 +277,7 @@ func (s *Server) handleArticleDetail(w http.ResponseWriter, r *http.Request) {
276 "HasLiked": liked,277 "HasLiked": liked,
277 "Annotations": annotations,278 "Annotations": annotations,
278 "NextID": nextID,279 "NextID": nextID,
279- "NextSuffix": buildNavSuffix(fromFeedURL, navLiked),280+ "NextSuffix": buildNavSuffix(fromFeedURL, navLiked, navStatus),
280 })281 })
281 }282 }
282 283
@@ -478,7 +479,7 @@ func (s *Server) handleFetchContent(w http.ResponseWriter, r *http.Request) {
478 s.logger.Info("scraped article content", "id", id, "url", article.URL.String, "content_len", len(cleaned))479 s.logger.Info("scraped article content", "id", id, "url", article.URL.String, "content_len", len(cleaned))
479 }480 }
480 481
481-func buildNavSuffix(feedURL string, liked bool) string {482+func buildNavSuffix(feedURL string, liked bool, status string) string {
482 v := url.Values{}483 v := url.Values{}
483 if feedURL != "" {484 if feedURL != "" {
484 v.Set("from_feed", feedURL)485 v.Set("from_feed", feedURL)
@@ -486,6 +487,9 @@ func buildNavSuffix(feedURL string, liked bool) string {
486 if liked {487 if liked {
487 v.Set("liked", "1")488 v.Set("liked", "1")
488 }489 }
490+ if status != "" {
491+ v.Set("status", status)
492+ }
489 if len(v) == 0 {493 if len(v) == 0 {
490 return ""494 return ""
491 }495 }