aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Maxim Baz <github@maximbaz.com>2019-10-30 05:44:35 +0100
committerGravatar Frédéric Guillot <fred@miniflux.net>2019-10-29 21:44:35 -0700
commite38333e272b24b6fcfa5399aa944f771558eb7aa (patch)
tree2ce26220cebdcafc01ba89fb59fa5a09da1268e7
parent2eb2441f2ba9fcb50d17d8f7deead756187b3586 (diff)
Show unread counters on feeds page
-rw-r--r--locale/translations.go27
-rw-r--r--locale/translations/de_DE.json1
-rw-r--r--locale/translations/en_US.json1
-rw-r--r--locale/translations/es_ES.json1
-rw-r--r--locale/translations/fr_FR.json1
-rw-r--r--locale/translations/it_IT.json1
-rw-r--r--locale/translations/nl_NL.json1
-rw-r--r--locale/translations/pl_PL.json1
-rw-r--r--locale/translations/ru_RU.json1
-rw-r--r--locale/translations/zh_CN.json1
-rw-r--r--model/feed.go2
-rw-r--r--storage/feed.go74
-rw-r--r--template/html/feeds.html5
-rw-r--r--template/views.go7
-rw-r--r--ui/feed_list.go2
15 files changed, 115 insertions, 11 deletions
diff --git a/locale/translations.go b/locale/translations.go
index 8451de3..49bee8a 100644
--- a/locale/translations.go
+++ b/locale/translations.go
@@ -86,6 +86,7 @@ var translations = map[string]string{
"page.edit_user.title": "Benutzer bearbeiten: %s",
"page.feeds.title": "Abonnements",
"page.feeds.last_check": "Letzte Aktualisierung:",
+ "page.feeds.unread": "Ungelesen:",
"page.feeds.error_count": [
"%d Fehler",
"%d Fehler"
@@ -387,6 +388,7 @@ var translations = map[string]string{
"page.edit_user.title": "Edit User: %s",
"page.feeds.title": "Feeds",
"page.feeds.last_check": "Last check:",
+ "page.feeds.unread": "Unread:",
"page.feeds.error_count": [
"%d error",
"%d errors"
@@ -668,6 +670,7 @@ var translations = map[string]string{
"page.edit_user.title": "Editar usuario: %s",
"page.feeds.title": "Fuentes",
"page.feeds.last_check": "Última verificación:",
+ "page.feeds.unread": "No leídos:",
"page.feeds.error_count": [
"%d error",
"%d errores"
@@ -949,6 +952,7 @@ var translations = map[string]string{
"page.edit_user.title": "Modification de l'utilisateur : %s",
"page.feeds.title": "Abonnements",
"page.feeds.last_check": "Dernière vérification :",
+ "page.feeds.unread": "Non lus:",
"page.feeds.error_count": [
"%d erreur",
"%d erreurs"
@@ -1250,6 +1254,7 @@ var translations = map[string]string{
"page.edit_user.title": "Modifica utente: %s",
"page.feeds.title": "Feed",
"page.feeds.last_check": "Ultimo controllo:",
+ "page.feeds.unread": "Da leggere:",
"page.feeds.error_count": [
"%d errore",
"%d errori"
@@ -1531,6 +1536,7 @@ var translations = map[string]string{
"page.edit_user.title": "Bewerk gebruiker: %s",
"page.feeds.title": "Feeds",
"page.feeds.last_check": "Laatste update:",
+ "page.feeds.unread": "Ongelezen:",
"page.feeds.error_count": [
"%d error",
"%d errors"
@@ -1831,6 +1837,7 @@ var translations = map[string]string{
"page.edit_user.title": "Edytuj użytkownika: %s",
"page.feeds.title": "Kanały",
"page.feeds.last_check": "Ostatnia aktualizacja:",
+ "page.feeds.unread": "Nieprzeczytane:",
"page.feeds.error_count": [
"%d błąd",
"%d błąd",
@@ -2138,6 +2145,7 @@ var translations = map[string]string{
"page.edit_user.title": "Изменить пользователя: %s",
"page.feeds.title": "Подписки",
"page.feeds.last_check": "Последняя проверка:",
+ "page.feeds.unread": "Непрочитано:",
"page.feeds.error_count": [
"%d ошибка",
"%d ошибки",
@@ -2425,6 +2433,7 @@ var translations = map[string]string{
"page.edit_user.title": "编辑用户 : %s",
"page.feeds.title": "源",
"page.feeds.last_check": "最后检查时间:",
+ "page.feeds.unread": "未读:",
"page.feeds.error_count": [
"%d 错误"
],
@@ -2638,13 +2647,13 @@ var translations = map[string]string{
}
var translationsChecksums = map[string]string{
- "de_DE": "52c82c151a27455501e54a4ea20339c965f030d7204ae9f55bf2639ef396b015",
- "en_US": "ef73c3934c5df6c2346f96a4eb4b308f84404c58029aac2ee6859bc205ecb6b3",
- "es_ES": "567fad5046d07efd69b9d29a3e8fa05503f935c02624c71851d9b1b3a8fa82d5",
- "fr_FR": "11a3f01603a73b4a0c2921aea592bdb24086286f4f1343df4adaeb4a1471c1b9",
- "it_IT": "19b9614980ded9ee4a5eea1f6623a8d2d4b763ffe81eae633d8c768bb58d6aea",
- "nl_NL": "a91e2195ac0731a3788405a51c4201e1a89dcce35ef792356e8c17adb57aee97",
- "pl_PL": "097bc9beac12f33d3a5e5ee98ccba0875e4d1c1bf13e38251a66ac450834c5b3",
- "ru_RU": "b253bf709a2f4bcac2f894bd1797247481fa7c6b70a0a0d8785d8680be83bac8",
- "zh_CN": "5004e07fa535ea56e7fbe1501bb8ff4191d1d214e51b4590110b660994c39f0d",
+ "de_DE": "c743f9eeca5d486c7b788e6ab20cf9f859e6c2138563d09599220fe40b3e25b5",
+ "en_US": "7992fd4e6fafceccbcf0b0972f0c085ad9a0eb7507de60eac407882c1f6457f5",
+ "es_ES": "e97765769afac01f4fd4cf868fa75657bd4d4e63999d9145a42d4de4248a9b2a",
+ "fr_FR": "50146f82d9b8e9ab69a5b3950827f7db47ba590ef074cf7f78b18f7e26fb0074",
+ "it_IT": "6a9f44c98b0dc8ab34306868bb9f93c4e511579a45c1fa8a48d637e10b2feca6",
+ "nl_NL": "afa731bd75e18b9483e9c6842b647f9d85405994ceca42f24b314bc967680606",
+ "pl_PL": "40aa0998688fb8dc1a308cda35bcea04be16c852944088c844c676c601a90bbd",
+ "ru_RU": "a1c72bb9ab48cf1b4fb47bfed081df75e391bb8d5c8b70036c1bdd38c57b6cb3",
+ "zh_CN": "a349de59436db0dc07172de89a481d95a660af206b13ae0de236a0cb8e31014b",
}
diff --git a/locale/translations/de_DE.json b/locale/translations/de_DE.json
index be7e7ee..42adabe 100644
--- a/locale/translations/de_DE.json
+++ b/locale/translations/de_DE.json
@@ -81,6 +81,7 @@
"page.edit_user.title": "Benutzer bearbeiten: %s",
"page.feeds.title": "Abonnements",
"page.feeds.last_check": "Letzte Aktualisierung:",
+ "page.feeds.unread": "Ungelesen:",
"page.feeds.error_count": [
"%d Fehler",
"%d Fehler"
diff --git a/locale/translations/en_US.json b/locale/translations/en_US.json
index 9b31ed2..576c144 100644
--- a/locale/translations/en_US.json
+++ b/locale/translations/en_US.json
@@ -81,6 +81,7 @@
"page.edit_user.title": "Edit User: %s",
"page.feeds.title": "Feeds",
"page.feeds.last_check": "Last check:",
+ "page.feeds.unread": "Unread:",
"page.feeds.error_count": [
"%d error",
"%d errors"
diff --git a/locale/translations/es_ES.json b/locale/translations/es_ES.json
index 70337a4..a1973d6 100644
--- a/locale/translations/es_ES.json
+++ b/locale/translations/es_ES.json
@@ -81,6 +81,7 @@
"page.edit_user.title": "Editar usuario: %s",
"page.feeds.title": "Fuentes",
"page.feeds.last_check": "Última verificación:",
+ "page.feeds.unread": "No leídos:",
"page.feeds.error_count": [
"%d error",
"%d errores"
diff --git a/locale/translations/fr_FR.json b/locale/translations/fr_FR.json
index 26f35e5..04fdc6f 100644
--- a/locale/translations/fr_FR.json
+++ b/locale/translations/fr_FR.json
@@ -81,6 +81,7 @@
"page.edit_user.title": "Modification de l'utilisateur : %s",
"page.feeds.title": "Abonnements",
"page.feeds.last_check": "Dernière vérification :",
+ "page.feeds.unread": "Non lus:",
"page.feeds.error_count": [
"%d erreur",
"%d erreurs"
diff --git a/locale/translations/it_IT.json b/locale/translations/it_IT.json
index c8c0a43..86d2d94 100644
--- a/locale/translations/it_IT.json
+++ b/locale/translations/it_IT.json
@@ -81,6 +81,7 @@
"page.edit_user.title": "Modifica utente: %s",
"page.feeds.title": "Feed",
"page.feeds.last_check": "Ultimo controllo:",
+ "page.feeds.unread": "Da leggere:",
"page.feeds.error_count": [
"%d errore",
"%d errori"
diff --git a/locale/translations/nl_NL.json b/locale/translations/nl_NL.json
index 271fffc..ca82e2e 100644
--- a/locale/translations/nl_NL.json
+++ b/locale/translations/nl_NL.json
@@ -81,6 +81,7 @@
"page.edit_user.title": "Bewerk gebruiker: %s",
"page.feeds.title": "Feeds",
"page.feeds.last_check": "Laatste update:",
+ "page.feeds.unread": "Ongelezen:",
"page.feeds.error_count": [
"%d error",
"%d errors"
diff --git a/locale/translations/pl_PL.json b/locale/translations/pl_PL.json
index f4b7ec7..fc3bc3d 100644
--- a/locale/translations/pl_PL.json
+++ b/locale/translations/pl_PL.json
@@ -82,6 +82,7 @@
"page.edit_user.title": "Edytuj użytkownika: %s",
"page.feeds.title": "Kanały",
"page.feeds.last_check": "Ostatnia aktualizacja:",
+ "page.feeds.unread": "Nieprzeczytane:",
"page.feeds.error_count": [
"%d błąd",
"%d błąd",
diff --git a/locale/translations/ru_RU.json b/locale/translations/ru_RU.json
index 1e1fa89..ae5a68a 100644
--- a/locale/translations/ru_RU.json
+++ b/locale/translations/ru_RU.json
@@ -82,6 +82,7 @@
"page.edit_user.title": "Изменить пользователя: %s",
"page.feeds.title": "Подписки",
"page.feeds.last_check": "Последняя проверка:",
+ "page.feeds.unread": "Непрочитано:",
"page.feeds.error_count": [
"%d ошибка",
"%d ошибки",
diff --git a/locale/translations/zh_CN.json b/locale/translations/zh_CN.json
index a690187..99c74b5 100644
--- a/locale/translations/zh_CN.json
+++ b/locale/translations/zh_CN.json
@@ -80,6 +80,7 @@
"page.edit_user.title": "编辑用户 : %s",
"page.feeds.title": "源",
"page.feeds.last_check": "最后检查时间:",
+ "page.feeds.unread": "未读:",
"page.feeds.error_count": [
"%d 错误"
],
diff --git a/model/feed.go b/model/feed.go
index 4b67cb1..0e25d7b 100644
--- a/model/feed.go
+++ b/model/feed.go
@@ -33,6 +33,8 @@ type Feed struct {
Category *Category `json:"category,omitempty"`
Entries Entries `json:"entries,omitempty"`
Icon *FeedIcon `json:"icon"`
+ UnreadCount int `json:"unread_count"`
+ ReadCount int `json:"read_count"`
}
func (f *Feed) String() string {
diff --git a/storage/feed.go b/storage/feed.go
index 5b98b82..45ca9be 100644
--- a/storage/feed.go
+++ b/storage/feed.go
@@ -121,6 +121,80 @@ func (s *Storage) Feeds(userID int64) (model.Feeds, error) {
return feeds, nil
}
+// FeedsWithCounters returns all feeds of the given user with counters of read and unread entries.
+func (s *Storage) FeedsWithCounters(userID int64) (model.Feeds, error) {
+ feeds := make(model.Feeds, 0)
+ query := `SELECT
+ f.id, f.feed_url, f.site_url, f.title, f.etag_header, f.last_modified_header,
+ f.user_id, f.checked_at at time zone u.timezone,
+ f.parsing_error_count, f.parsing_error_msg,
+ f.scraper_rules, f.rewrite_rules, f.crawler, f.user_agent,
+ f.username, f.password, f.disabled,
+ f.category_id, c.title as category_title,
+ fi.icon_id,
+ u.timezone,
+ (SELECT count(*) FROM entries WHERE entries.feed_id=f.id AND status='unread') as unread_count,
+ (SELECT count(*) FROM entries WHERE entries.feed_id=f.id AND status='read') as read_count
+ FROM feeds f
+ LEFT JOIN categories c ON c.id=f.category_id
+ LEFT JOIN feed_icons fi ON fi.feed_id=f.id
+ LEFT JOIN users u ON u.id=f.user_id
+ WHERE f.user_id=$1
+ ORDER BY f.parsing_error_count DESC, unread_count DESC, lower(f.title) ASC`
+
+ rows, err := s.db.Query(query, userID)
+ if err != nil {
+ return nil, fmt.Errorf("unable to fetch feeds: %v", err)
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var feed model.Feed
+ var iconID interface{}
+ var tz string
+ feed.Category = &model.Category{UserID: userID}
+
+ err := rows.Scan(
+ &feed.ID,
+ &feed.FeedURL,
+ &feed.SiteURL,
+ &feed.Title,
+ &feed.EtagHeader,
+ &feed.LastModifiedHeader,
+ &feed.UserID,
+ &feed.CheckedAt,
+ &feed.ParsingErrorCount,
+ &feed.ParsingErrorMsg,
+ &feed.ScraperRules,
+ &feed.RewriteRules,
+ &feed.Crawler,
+ &feed.UserAgent,
+ &feed.Username,
+ &feed.Password,
+ &feed.Disabled,
+ &feed.Category.ID,
+ &feed.Category.Title,
+ &iconID,
+ &tz,
+ &feed.UnreadCount,
+ &feed.ReadCount,
+ )
+
+ if err != nil {
+ return nil, fmt.Errorf("unable to fetch feeds row: %v", err)
+ }
+
+ if iconID != nil {
+ feed.Icon = &model.FeedIcon{FeedID: feed.ID, IconID: iconID.(int64)}
+ }
+
+ feed.CheckedAt = timezone.Convert(tz, feed.CheckedAt)
+ feeds = append(feeds, &feed)
+ }
+
+ return feeds, nil
+}
+
// FeedByID returns a feed by the ID.
func (s *Storage) FeedByID(userID, feedID int64) (*model.Feed, error) {
var feed model.Feed
diff --git a/template/html/feeds.html b/template/html/feeds.html
index e4a3231..f676f23 100644
--- a/template/html/feeds.html
+++ b/template/html/feeds.html
@@ -45,6 +45,11 @@
<li>
{{ t "page.feeds.last_check" }} <time datetime="{{ isodate .CheckedAt }}" title="{{ isodate .CheckedAt }}">{{ elapsed $.user.Timezone .CheckedAt }}</time>
</li>
+ {{ if gt .UnreadCount 0 }}
+ <li>
+ {{ t "page.feeds.unread" }} <span class="unread-counter">{{ .UnreadCount }}</span>
+ </li>
+ {{ end }}
</ul>
<ul>
<li>
diff --git a/template/views.go b/template/views.go
index c951f8a..41adbc6 100644
--- a/template/views.go
+++ b/template/views.go
@@ -851,6 +851,11 @@ var templateViewsMap = map[string]string{
<li>
{{ t "page.feeds.last_check" }} <time datetime="{{ isodate .CheckedAt }}" title="{{ isodate .CheckedAt }}">{{ elapsed $.user.Timezone .CheckedAt }}</time>
</li>
+ {{ if gt .UnreadCount 0 }}
+ <li>
+ {{ t "page.feeds.unread" }} <span class="unread-counter">{{ .UnreadCount }}</span>
+ </li>
+ {{ end }}
</ul>
<ul>
<li>
@@ -1483,7 +1488,7 @@ var templateViewsMapChecksums = map[string]string{
"edit_user": "f4f99412ba771cfca2a2a42778b023b413c5494e9a287053ba8cf380c2865c5f",
"entry": "24aeba26ef9a51ce585ca5c4af090f1de7d7bfd7f1e3ff1b63af520e2afa76bd",
"feed_entries": "9c70b82f55e4b311eff20be1641733612e3c1b406ce8010861e4c417d97b6dcc",
- "feeds": "fa2dad422445eca898c1daa4ab742691207a8c0d3c274eed84462bc610d22219",
+ "feeds": "55317035a4c008a720294c1858e9dc626f19e222ae41498db67dbb537ba7a456",
"history_entries": "87e17d39de70eb3fdbc4000326283be610928758eae7924e4b08dcb446f3b6a9",
"import": "5eb56cecaa4d369b9acc991a82be7617710c551089a2e99d34ce8b6e5c37df0a",
"integrations": "f85b4a48ab1fc13b8ca94bfbbc44bd5e8784f35b26a63ec32cbe82b96b45e008",
diff --git a/ui/feed_list.go b/ui/feed_list.go
index 0c2c546..7c7b922 100644
--- a/ui/feed_list.go
+++ b/ui/feed_list.go
@@ -20,7 +20,7 @@ func (h *handler) showFeedsPage(w http.ResponseWriter, r *http.Request) {
return
}
- feeds, err := h.store.Feeds(user.ID)
+ feeds, err := h.store.FeedsWithCounters(user.ID)
if err != nil {
html.ServerError(w, r, err)
return