nav_metadata.go 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package storage // import "miniflux.app/v2/internal/storage"
  4. import (
  5. "log/slog"
  6. "miniflux.app/v2/internal/config"
  7. )
  8. type NavMetadata struct {
  9. CountUnread int
  10. CountErrorFeeds int
  11. HasSaveEntry bool
  12. }
  13. // GetNavMetadata returns the navigation metadata for the given user in a
  14. // single SQL query.
  15. func (s *Storage) GetNavMetadata(userID int64) (NavMetadata, error) {
  16. query := `
  17. SELECT
  18. (SELECT count(*)
  19. FROM entries e
  20. JOIN feeds f ON f.id = e.feed_id
  21. JOIN categories c ON c.id = f.category_id
  22. WHERE e.user_id = $1
  23. AND e.status = 'unread'
  24. AND f.hide_globally IS FALSE
  25. AND c.hide_globally IS FALSE
  26. ) AS count_unread,
  27. (SELECT EXISTS(
  28. SELECT 1
  29. FROM integrations
  30. WHERE user_id = $1
  31. AND (
  32. pinboard_enabled='t' OR
  33. instapaper_enabled='t' OR
  34. wallabag_enabled='t' OR
  35. notion_enabled='t' OR
  36. nunux_keeper_enabled='t' OR
  37. espial_enabled='t' OR
  38. readwise_enabled='t' OR
  39. linkace_enabled='t' OR
  40. linkding_enabled='t' OR
  41. linktaco_enabled='t' OR
  42. linkwarden_enabled='t' OR
  43. apprise_enabled='t' OR
  44. shiori_enabled='t' OR
  45. readeck_enabled='t' OR
  46. shaarli_enabled='t' OR
  47. webhook_enabled='t' OR
  48. omnivore_enabled='t' OR
  49. karakeep_enabled='t' OR
  50. raindrop_enabled='t' OR
  51. betula_enabled='t' OR
  52. cubox_enabled='t' OR
  53. discord_enabled='t' OR
  54. slack_enabled='t' OR
  55. archiveorg_enabled='t'
  56. )
  57. )) AS has_save_entry,
  58. `
  59. if config.Opts.PollingParsingErrorLimit() == 0 {
  60. // zero means unlimited amount of accepted errors
  61. query += `(SELECT $2) AS count_error_feeds`
  62. } else {
  63. query += `(SELECT count(*)
  64. FROM feeds
  65. WHERE user_id = $1
  66. AND parsing_error_count >= $2
  67. ) AS count_error_feeds
  68. `
  69. }
  70. var countUnread, countErrorFeeds int
  71. var hasSaveEntry bool
  72. err := s.db.QueryRow(query, userID, config.Opts.PollingParsingErrorLimit()).Scan(
  73. &countUnread,
  74. &hasSaveEntry,
  75. &countErrorFeeds,
  76. )
  77. if err != nil {
  78. slog.Error("Unable to fetch navigation metadata",
  79. slog.Int64("user_id", userID),
  80. slog.Any("error", err),
  81. )
  82. return NavMetadata{}, err
  83. }
  84. return NavMetadata{
  85. CountUnread: countUnread,
  86. CountErrorFeeds: countErrorFeeds,
  87. HasSaveEntry: hasSaveEntry,
  88. }, nil
  89. }