diff --git a/locale/translations.go b/locale/translations.go index 8451de3c..49bee8af 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 be7e7ee5..42adabed 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 9b31ed2a..576c1440 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 70337a4e..a1973d6a 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 26f35e5c..04fdc6f8 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 c8c0a434..86d2d945 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 271fffc9..ca82e2ed 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 f4b7ec74..fc3bc3d4 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 1e1fa898..ae5a68a2 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 a6901876..99c74b58 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 4b67cb1c..0e25d7b4 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 5b98b824..45ca9bea 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 e4a32317..f676f233 100644 --- a/template/html/feeds.html +++ b/template/html/feeds.html @@ -45,6 +45,11 @@