Show unread counters on feeds page

This commit is contained in:
Maxim Baz 2019-10-30 05:44:35 +01:00 committed by Frédéric Guillot
parent 2eb2441f2b
commit e38333e272
15 changed files with 115 additions and 11 deletions

View file

@ -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",
}

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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",

View file

@ -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 ошибки",

View file

@ -80,6 +80,7 @@
"page.edit_user.title": "编辑用户 : %s",
"page.feeds.title": "源",
"page.feeds.last_check": "最后检查时间:",
"page.feeds.unread": "未读:",
"page.feeds.error_count": [
"%d 错误"
],

View file

@ -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 {

View file

@ -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

View file

@ -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>

View file

@ -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",

View file

@ -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