Make default home page configurable

This commit is contained in:
Romain de Laage 2022-07-20 22:07:55 +02:00 committed by Frédéric Guillot
parent 45a9fd5af6
commit 03a1cfcd5e
30 changed files with 125 additions and 14 deletions

View file

@ -38,6 +38,7 @@ type User struct {
DisplayMode string `json:"display_mode"` DisplayMode string `json:"display_mode"`
DefaultReadingSpeed int `json:"default_reading_speed"` DefaultReadingSpeed int `json:"default_reading_speed"`
CJKReadingSpeed int `json:"cjk_reading_speed"` CJKReadingSpeed int `json:"cjk_reading_speed"`
DefaultHomePage string `json:"default_home_page"`
} }
func (u User) String() string { func (u User) String() string {
@ -73,6 +74,7 @@ type UserModificationRequest struct {
DisplayMode *string `json:"display_mode"` DisplayMode *string `json:"display_mode"`
DefaultReadingSpeed *int `json:"default_reading_speed"` DefaultReadingSpeed *int `json:"default_reading_speed"`
CJKReadingSpeed *int `json:"cjk_reading_speed"` CJKReadingSpeed *int `json:"cjk_reading_speed"`
DefaultHomePage *string `json:"default_home_page"`
} }
// Users represents a list of users. // Users represents a list of users.

View file

@ -604,4 +604,10 @@ var migrations = []func(tx *sql.Tx) error{
`) `)
return return
}, },
func(tx *sql.Tx) (err error) {
_, err = tx.Exec(`
ALTER TABLE users ADD COLUMN default_home_page text default 'unread';
`)
return
},
} }

View file

@ -263,6 +263,7 @@
"error.invalid_timezone": "Ungültige Zeitzone.", "error.invalid_timezone": "Ungültige Zeitzone.",
"error.invalid_entry_direction": "Ungültige Sortierreihenfolge.", "error.invalid_entry_direction": "Ungültige Sortierreihenfolge.",
"error.invalid_display_mode": "Ungültiger Web-App-Anzeigemodus.", "error.invalid_display_mode": "Ungültiger Web-App-Anzeigemodus.",
"error.invalid_default_home_page": "Ungültige Standard-Startseite!",
"form.feed.label.title": "Titel", "form.feed.label.title": "Titel",
"form.feed.label.site_url": "Webseite-URL", "form.feed.label.site_url": "Webseite-URL",
"form.feed.label.feed_url": "Abonnement-URL", "form.feed.label.feed_url": "Abonnement-URL",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "Geschätzte Lesezeit für Artikel anzeigen", "form.prefs.label.show_reading_time": "Geschätzte Lesezeit für Artikel anzeigen",
"form.prefs.label.custom_css": "Benutzerdefiniertes CSS", "form.prefs.label.custom_css": "Benutzerdefiniertes CSS",
"form.prefs.label.entry_order": "Eintrag Sortierspalte", "form.prefs.label.entry_order": "Eintrag Sortierspalte",
"form.prefs.label.default_home_page": "Standard Startseite",
"form.import.label.file": "OPML Datei", "form.import.label.file": "OPML Datei",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Fever API aktivieren", "form.integration.fever_activate": "Fever API aktivieren",

View file

@ -241,6 +241,7 @@
"error.invalid_timezone": "Μη έγκυρη ζώνη ώρας.", "error.invalid_timezone": "Μη έγκυρη ζώνη ώρας.",
"error.invalid_entry_direction": "Μη έγκυρη κατεύθυνση ταξινόμησης άρθρων.", "error.invalid_entry_direction": "Μη έγκυρη κατεύθυνση ταξινόμησης άρθρων.",
"error.invalid_display_mode": "Μη έγκυρη λειτουργία εμφάνισης εφαρμογών ιστού.", "error.invalid_display_mode": "Μη έγκυρη λειτουργία εμφάνισης εφαρμογών ιστού.",
"error.invalid_default_home_page": "Μη έγκυρη προεπιλεγμένη αρχική σελίδα!",
"error.empty_file": "Αυτό το αρχείο είναι κενό.", "error.empty_file": "Αυτό το αρχείο είναι κενό.",
"error.bad_credentials": "Μη έγκυρο όνομα χρήστη ή κωδικό πρόσβασης.", "error.bad_credentials": "Μη έγκυρο όνομα χρήστη ή κωδικό πρόσβασης.",
"error.fields_mandatory": "Όλα τα πεδία είναι υποχρεωτικά.", "error.fields_mandatory": "Όλα τα πεδία είναι υποχρεωτικά.",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "Εμφάνιση εκτιμώμενου χρόνου ανάγνωσης για άρθρα", "form.prefs.label.show_reading_time": "Εμφάνιση εκτιμώμενου χρόνου ανάγνωσης για άρθρα",
"form.prefs.label.custom_css": "Προσαρμοσμένο CSS", "form.prefs.label.custom_css": "Προσαρμοσμένο CSS",
"form.prefs.label.entry_order": "Στήλη ταξινόμησης εισόδου", "form.prefs.label.entry_order": "Στήλη ταξινόμησης εισόδου",
"form.prefs.label.default_home_page": "Προεπιλεγμένη αρχική σελίδα",
"form.import.label.file": "Αρχείο OPML", "form.import.label.file": "Αρχείο OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Ενεργοποιήστε το Fever API", "form.integration.fever_activate": "Ενεργοποιήστε το Fever API",

View file

@ -241,6 +241,7 @@
"error.invalid_timezone": "Invalid timezone.", "error.invalid_timezone": "Invalid timezone.",
"error.invalid_entry_direction": "Invalid entry direction.", "error.invalid_entry_direction": "Invalid entry direction.",
"error.invalid_display_mode": "Invalid web app display mode.", "error.invalid_display_mode": "Invalid web app display mode.",
"error.invalid_default_home_page": "Invalid default homepage!",
"error.empty_file": "This file is empty.", "error.empty_file": "This file is empty.",
"error.bad_credentials": "Invalid username or password.", "error.bad_credentials": "Invalid username or password.",
"error.fields_mandatory": "All fields are mandatory.", "error.fields_mandatory": "All fields are mandatory.",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "Show estimated reading time for articles", "form.prefs.label.show_reading_time": "Show estimated reading time for articles",
"form.prefs.label.custom_css": "Custom CSS", "form.prefs.label.custom_css": "Custom CSS",
"form.prefs.label.entry_order": "Entry Sorting Column", "form.prefs.label.entry_order": "Entry Sorting Column",
"form.prefs.label.default_home_page": "Default home page",
"form.import.label.file": "OPML file", "form.import.label.file": "OPML file",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Activate Fever API", "form.integration.fever_activate": "Activate Fever API",

View file

@ -263,6 +263,7 @@
"error.invalid_timezone": "Zona horaria no válida.", "error.invalid_timezone": "Zona horaria no válida.",
"error.invalid_entry_direction": "Dirección de entrada no válida.", "error.invalid_entry_direction": "Dirección de entrada no válida.",
"error.invalid_display_mode": "Modo de visualización de la aplicación web no válido.", "error.invalid_display_mode": "Modo de visualización de la aplicación web no válido.",
"error.invalid_default_home_page": "¡Página de inicio por defecto inválida!",
"form.feed.label.title": "Título", "form.feed.label.title": "Título",
"form.feed.label.site_url": "URL del sitio", "form.feed.label.site_url": "URL del sitio",
"form.feed.label.feed_url": "URL de la fuente", "form.feed.label.feed_url": "URL de la fuente",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "Mostrar el tiempo estimado de lectura de los artículos", "form.prefs.label.show_reading_time": "Mostrar el tiempo estimado de lectura de los artículos",
"form.prefs.label.custom_css": "CSS personalizado", "form.prefs.label.custom_css": "CSS personalizado",
"form.prefs.label.entry_order": "Columna de clasificación de entradas", "form.prefs.label.entry_order": "Columna de clasificación de entradas",
"form.prefs.label.default_home_page": "Página de inicio por defecto",
"form.import.label.file": "Archivo OPML", "form.import.label.file": "Archivo OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Activar API de Fever", "form.integration.fever_activate": "Activar API de Fever",

View file

@ -241,6 +241,7 @@
"error.invalid_timezone": "Virheellinen aikavyöhyke.", "error.invalid_timezone": "Virheellinen aikavyöhyke.",
"error.invalid_entry_direction": "Invalid entry direction.", "error.invalid_entry_direction": "Invalid entry direction.",
"error.invalid_display_mode": "Virheellinen verkkosovelluksen näyttötila.", "error.invalid_display_mode": "Virheellinen verkkosovelluksen näyttötila.",
"error.invalid_default_home_page": "Väärä oletusarvoinen kotisivu!",
"error.empty_file": "Tiedosto on tyhjä.", "error.empty_file": "Tiedosto on tyhjä.",
"error.bad_credentials": "Virheellinen käyttäjänimi tai salasana.", "error.bad_credentials": "Virheellinen käyttäjänimi tai salasana.",
"error.fields_mandatory": "Kaikki kentät ovat pakollisia.", "error.fields_mandatory": "Kaikki kentät ovat pakollisia.",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "Näytä artikkeleiden arvioitu lukuaika", "form.prefs.label.show_reading_time": "Näytä artikkeleiden arvioitu lukuaika",
"form.prefs.label.custom_css": "Mukautettu CSS", "form.prefs.label.custom_css": "Mukautettu CSS",
"form.prefs.label.entry_order": "Lajittele sarakkeen mukaan", "form.prefs.label.entry_order": "Lajittele sarakkeen mukaan",
"form.prefs.label.default_home_page": "Oletusarvoinen etusivu",
"form.import.label.file": "OPML-tiedosto", "form.import.label.file": "OPML-tiedosto",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Ota Fever API käyttöön", "form.integration.fever_activate": "Ota Fever API käyttöön",

View file

@ -263,6 +263,7 @@
"error.invalid_timezone": "Fuseau horaire non valide.", "error.invalid_timezone": "Fuseau horaire non valide.",
"error.invalid_entry_direction": "Ordre de trie non valide.", "error.invalid_entry_direction": "Ordre de trie non valide.",
"error.invalid_display_mode": "Mode d'affichage de l'application web non valide.", "error.invalid_display_mode": "Mode d'affichage de l'application web non valide.",
"error.invalid_default_home_page": "Page d'accueil par défaut invalide !",
"form.feed.label.title": "Titre", "form.feed.label.title": "Titre",
"form.feed.label.site_url": "URL du site web", "form.feed.label.site_url": "URL du site web",
"form.feed.label.feed_url": "URL du flux", "form.feed.label.feed_url": "URL du flux",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "Afficher le temps de lecture estimé des articles", "form.prefs.label.show_reading_time": "Afficher le temps de lecture estimé des articles",
"form.prefs.label.custom_css": "CSS personnalisé", "form.prefs.label.custom_css": "CSS personnalisé",
"form.prefs.label.entry_order": "Colonne de tri des entrées", "form.prefs.label.entry_order": "Colonne de tri des entrées",
"form.prefs.label.default_home_page": "Page d'accueil par défaut",
"form.import.label.file": "Fichier OPML", "form.import.label.file": "Fichier OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Activer l'API de Fever", "form.integration.fever_activate": "Activer l'API de Fever",

View file

@ -241,6 +241,7 @@
"error.invalid_timezone": "अमान्य समयक्षेत्र.", "error.invalid_timezone": "अमान्य समयक्षेत्र.",
"error.invalid_entry_direction": "अमान्य प्रवेश दिशा।", "error.invalid_entry_direction": "अमान्य प्रवेश दिशा।",
"error.invalid_display_mode": "अमान्य वेब ऐप्लिकेशन प्रदर्शन मोड.", "error.invalid_display_mode": "अमान्य वेब ऐप्लिकेशन प्रदर्शन मोड.",
"error.invalid_default_home_page": "अमान्य डिफ़ॉल्ट मुखपृष्ठ!",
"error.empty_file": "यह फ़ाइल खाली है।", "error.empty_file": "यह फ़ाइल खाली है।",
"error.bad_credentials": "अमान्य उपयोगकर्ता नाम या पासवर्ड।", "error.bad_credentials": "अमान्य उपयोगकर्ता नाम या पासवर्ड।",
"error.fields_mandatory": "सभी फील्ड अनिवार्य।", "error.fields_mandatory": "सभी फील्ड अनिवार्य।",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "विषय के लिए अनुमानित पढ़ने का समय दिखाएं", "form.prefs.label.show_reading_time": "विषय के लिए अनुमानित पढ़ने का समय दिखाएं",
"form.prefs.label.custom_css": "कस्टम सीएसएस", "form.prefs.label.custom_css": "कस्टम सीएसएस",
"form.prefs.label.entry_order": "प्रवेश छँटाई कॉलम", "form.prefs.label.entry_order": "प्रवेश छँटाई कॉलम",
"form.prefs.label.default_home_page": "डिफ़ॉल्ट होमपेज़",
"form.import.label.file": "ओपीएमएल फ़ाइल", "form.import.label.file": "ओपीएमएल फ़ाइल",
"form.import.label.url": "यूआरएल", "form.import.label.url": "यूआरएल",
"form.integration.fever_activate": "फीवर एपीआई सक्रिय करें", "form.integration.fever_activate": "फीवर एपीआई सक्रिय करें",

View file

@ -263,6 +263,7 @@
"error.invalid_timezone": "Fuso orario non valido.", "error.invalid_timezone": "Fuso orario non valido.",
"error.invalid_entry_direction": "Ordinamento non valido.", "error.invalid_entry_direction": "Ordinamento non valido.",
"error.invalid_display_mode": "Modalità di visualizzazione web app non valida.", "error.invalid_display_mode": "Modalità di visualizzazione web app non valida.",
"error.invalid_default_home_page": "Pagina iniziale predefinita non valida!",
"form.feed.label.title": "Titolo", "form.feed.label.title": "Titolo",
"form.feed.label.site_url": "URL del sito", "form.feed.label.site_url": "URL del sito",
"form.feed.label.feed_url": "URL del feed", "form.feed.label.feed_url": "URL del feed",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "Mostra il tempo di lettura stimato per gli articoli", "form.prefs.label.show_reading_time": "Mostra il tempo di lettura stimato per gli articoli",
"form.prefs.label.custom_css": "CSS personalizzati", "form.prefs.label.custom_css": "CSS personalizzati",
"form.prefs.label.entry_order": "Colonna di ordinamento delle voci", "form.prefs.label.entry_order": "Colonna di ordinamento delle voci",
"form.prefs.label.default_home_page": "Pagina iniziale predefinita",
"form.import.label.file": "File OPML", "form.import.label.file": "File OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Abilita l'API di Fever", "form.integration.fever_activate": "Abilita l'API di Fever",

View file

@ -263,6 +263,7 @@
"error.invalid_timezone": "タイムゾーンが無効です。", "error.invalid_timezone": "タイムゾーンが無効です。",
"error.invalid_entry_direction": "ソート順が無効です。", "error.invalid_entry_direction": "ソート順が無効です。",
"error.invalid_display_mode": "Webアプリの表示モードが無効です。", "error.invalid_display_mode": "Webアプリの表示モードが無効です。",
"error.invalid_default_home_page": "デフォルトのホームページが無効です",
"form.feed.label.title": "タイトル", "form.feed.label.title": "タイトル",
"form.feed.label.site_url": "サイト URL", "form.feed.label.site_url": "サイト URL",
"form.feed.label.feed_url": "フィード URL", "form.feed.label.feed_url": "フィード URL",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "記事の推定読書時間を表示する", "form.prefs.label.show_reading_time": "記事の推定読書時間を表示する",
"form.prefs.label.custom_css": "カスタムCSS", "form.prefs.label.custom_css": "カスタムCSS",
"form.prefs.label.entry_order": "エントリーソートカラム", "form.prefs.label.entry_order": "エントリーソートカラム",
"form.prefs.label.default_home_page": "デフォルトのトップページ",
"form.import.label.file": "OPML ファイル", "form.import.label.file": "OPML ファイル",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Fever API を有効にする", "form.integration.fever_activate": "Fever API を有効にする",

View file

@ -263,6 +263,7 @@
"error.invalid_timezone": "Ongeldige tijdzone.", "error.invalid_timezone": "Ongeldige tijdzone.",
"error.invalid_entry_direction": "Ongeldige sorteervolgorde.", "error.invalid_entry_direction": "Ongeldige sorteervolgorde.",
"error.invalid_display_mode": "Ongeldige weergavemodus voor webapp.", "error.invalid_display_mode": "Ongeldige weergavemodus voor webapp.",
"error.invalid_default_home_page": "Ongeldige standaard homepage!",
"form.feed.label.title": "Naam", "form.feed.label.title": "Naam",
"form.feed.label.site_url": "Website URL", "form.feed.label.site_url": "Website URL",
"form.feed.label.feed_url": "Feed URL", "form.feed.label.feed_url": "Feed URL",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "Toon geschatte leestijd voor artikelen", "form.prefs.label.show_reading_time": "Toon geschatte leestijd voor artikelen",
"form.prefs.label.custom_css": "Aangepaste CSS", "form.prefs.label.custom_css": "Aangepaste CSS",
"form.prefs.label.entry_order": "Ingang Sorteerkolom", "form.prefs.label.entry_order": "Ingang Sorteerkolom",
"form.prefs.label.default_home_page": "Standaard startpagina",
"form.import.label.file": "OPML-bestand", "form.import.label.file": "OPML-bestand",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Activeer Fever API", "form.integration.fever_activate": "Activeer Fever API",

View file

@ -265,6 +265,7 @@
"error.invalid_timezone": "Nieprawidłowa strefa czasowa.", "error.invalid_timezone": "Nieprawidłowa strefa czasowa.",
"error.invalid_entry_direction": "Nieprawidłowa kolejność sortowania.", "error.invalid_entry_direction": "Nieprawidłowa kolejność sortowania.",
"error.invalid_display_mode": "Nieprawidłowy tryb wyświetlania aplikacji internetowej.", "error.invalid_display_mode": "Nieprawidłowy tryb wyświetlania aplikacji internetowej.",
"error.invalid_default_home_page": "Nieprawidłowa domyślna strona główna!",
"form.feed.label.title": "Tytuł", "form.feed.label.title": "Tytuł",
"form.feed.label.site_url": "URL strony", "form.feed.label.site_url": "URL strony",
"form.feed.label.feed_url": "URL kanału", "form.feed.label.feed_url": "URL kanału",
@ -311,6 +312,7 @@
"form.prefs.select.created_time": "Czas utworzenia wpisu", "form.prefs.select.created_time": "Czas utworzenia wpisu",
"form.prefs.label.custom_css": "Niestandardowy CSS", "form.prefs.label.custom_css": "Niestandardowy CSS",
"form.prefs.label.entry_order": "Kolumna sortowania wpisów", "form.prefs.label.entry_order": "Kolumna sortowania wpisów",
"form.prefs.label.default_home_page": "Domyślna strona główna",
"form.import.label.file": "Plik OPML", "form.import.label.file": "Plik OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Aktywuj Fever API", "form.integration.fever_activate": "Aktywuj Fever API",

View file

@ -263,6 +263,7 @@
"error.invalid_timezone": "Fuso horário inválido.", "error.invalid_timezone": "Fuso horário inválido.",
"error.invalid_entry_direction": "Direção de entrada inválida.", "error.invalid_entry_direction": "Direção de entrada inválida.",
"error.invalid_display_mode": "Modo de exibição de aplicativo inválido da web.", "error.invalid_display_mode": "Modo de exibição de aplicativo inválido da web.",
"error.invalid_default_home_page": "Página inicial por defeito inválida!",
"form.feed.label.title": "Título", "form.feed.label.title": "Título",
"form.feed.label.site_url": "URL do site", "form.feed.label.site_url": "URL do site",
"form.feed.label.feed_url": "URL da fonte", "form.feed.label.feed_url": "URL da fonte",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "Mostrar tempo estimado de leitura de artigos", "form.prefs.label.show_reading_time": "Mostrar tempo estimado de leitura de artigos",
"form.prefs.label.custom_css": "CSS customizado", "form.prefs.label.custom_css": "CSS customizado",
"form.prefs.label.entry_order": "Coluna de Ordenação de Entrada", "form.prefs.label.entry_order": "Coluna de Ordenação de Entrada",
"form.prefs.label.default_home_page": "Página inicial predefinida",
"form.import.label.file": "Arquivo OPML", "form.import.label.file": "Arquivo OPML",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Ativar API do Fever", "form.integration.fever_activate": "Ativar API do Fever",

View file

@ -265,6 +265,7 @@
"error.invalid_timezone": "Неверный часовой пояс.", "error.invalid_timezone": "Неверный часовой пояс.",
"error.invalid_entry_direction": "Неверное направление входа.", "error.invalid_entry_direction": "Неверное направление входа.",
"error.invalid_display_mode": "Недопустимый режим отображения веб-приложения.", "error.invalid_display_mode": "Недопустимый режим отображения веб-приложения.",
"error.invalid_default_home_page": "Неверная домашняя страница по умолчанию!",
"form.feed.label.title": "Название", "form.feed.label.title": "Название",
"form.feed.label.site_url": "URL сайта", "form.feed.label.site_url": "URL сайта",
"form.feed.label.feed_url": "URL подписки", "form.feed.label.feed_url": "URL подписки",
@ -311,6 +312,7 @@
"form.prefs.label.show_reading_time": "Показать примерное время чтения статей", "form.prefs.label.show_reading_time": "Показать примерное время чтения статей",
"form.prefs.label.custom_css": "Пользовательские CSS", "form.prefs.label.custom_css": "Пользовательские CSS",
"form.prefs.label.entry_order": "Колонка сортировки ввода", "form.prefs.label.entry_order": "Колонка сортировки ввода",
"form.prefs.label.default_home_page": "Домашняя страница по умолчанию",
"form.import.label.file": "OPML файл", "form.import.label.file": "OPML файл",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Активировать Fever API", "form.integration.fever_activate": "Активировать Fever API",

View file

@ -241,6 +241,7 @@
"error.invalid_timezone": "Geçersiz saat dilimi", "error.invalid_timezone": "Geçersiz saat dilimi",
"error.invalid_entry_direction": "Geçersiz giriş yönü.", "error.invalid_entry_direction": "Geçersiz giriş yönü.",
"error.invalid_display_mode": "Geçersiz web uygulaması görüntüleme modu.", "error.invalid_display_mode": "Geçersiz web uygulaması görüntüleme modu.",
"error.invalid_default_home_page": "Geçersiz varsayılan ana sayfa!",
"error.empty_file": "Bu dosya boş.", "error.empty_file": "Bu dosya boş.",
"error.bad_credentials": "Geçersiz kullanıcı veya parola.", "error.bad_credentials": "Geçersiz kullanıcı veya parola.",
"error.fields_mandatory": "Tüm alanlar zorunlu.", "error.fields_mandatory": "Tüm alanlar zorunlu.",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "Makaleler için tahmini okuma süresini göster", "form.prefs.label.show_reading_time": "Makaleler için tahmini okuma süresini göster",
"form.prefs.label.custom_css": "Özel CSS", "form.prefs.label.custom_css": "Özel CSS",
"form.prefs.label.entry_order": "Giriş Sıralama Sütunu", "form.prefs.label.entry_order": "Giriş Sıralama Sütunu",
"form.prefs.label.default_home_page": "Varsayılan ana sayfa",
"form.import.label.file": "OPML dosyası", "form.import.label.file": "OPML dosyası",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "Fever API'yi Etkinleştir", "form.integration.fever_activate": "Fever API'yi Etkinleştir",

View file

@ -261,6 +261,7 @@
"error.invalid_timezone": "无效的时区。", "error.invalid_timezone": "无效的时区。",
"error.invalid_entry_direction": "无效的输入方向。", "error.invalid_entry_direction": "无效的输入方向。",
"error.invalid_display_mode": "无效的网页应用显示模式。", "error.invalid_display_mode": "无效的网页应用显示模式。",
"error.invalid_default_home_page": "无效的默认主页!",
"form.feed.label.title": "标题", "form.feed.label.title": "标题",
"form.feed.label.site_url": "源网站 URL", "form.feed.label.site_url": "源网站 URL",
"form.feed.label.feed_url": "订阅源 URL", "form.feed.label.feed_url": "订阅源 URL",
@ -307,6 +308,7 @@
"form.prefs.label.show_reading_time": "显示文章的预计阅读时间", "form.prefs.label.show_reading_time": "显示文章的预计阅读时间",
"form.prefs.label.custom_css": "自定义 CSS", "form.prefs.label.custom_css": "自定义 CSS",
"form.prefs.label.entry_order": "文章排序依据", "form.prefs.label.entry_order": "文章排序依据",
"form.prefs.label.default_home_page": "默认主页",
"form.import.label.file": "OPML 文件", "form.import.label.file": "OPML 文件",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "启用 Fever API", "form.integration.fever_activate": "启用 Fever API",

View file

@ -263,6 +263,7 @@
"error.invalid_timezone": "無效的時區。", "error.invalid_timezone": "無效的時區。",
"error.invalid_entry_direction": "無效的輸入方向。", "error.invalid_entry_direction": "無效的輸入方向。",
"error.invalid_display_mode": "無效的網頁應用顯示模式。", "error.invalid_display_mode": "無效的網頁應用顯示模式。",
"error.invalid_default_home_page": "默認主頁無效!",
"form.feed.label.title": "標題", "form.feed.label.title": "標題",
"form.feed.label.site_url": "網站 URL", "form.feed.label.site_url": "網站 URL",
"form.feed.label.feed_url": "訂閱Feed URL", "form.feed.label.feed_url": "訂閱Feed URL",
@ -309,6 +310,7 @@
"form.prefs.label.show_reading_time": "顯示文章的預計閱讀時間", "form.prefs.label.show_reading_time": "顯示文章的預計閱讀時間",
"form.prefs.label.custom_css": "自定義 CSS", "form.prefs.label.custom_css": "自定義 CSS",
"form.prefs.label.entry_order": "文章排序依據", "form.prefs.label.entry_order": "文章排序依據",
"form.prefs.label.default_home_page": "默認主頁",
"form.import.label.file": "OPML 檔案", "form.import.label.file": "OPML 檔案",
"form.import.label.url": "URL", "form.import.label.url": "URL",
"form.integration.fever_activate": "啟用 Fever API", "form.integration.fever_activate": "啟用 Fever API",

16
model/home_page.go Normal file
View file

@ -0,0 +1,16 @@
// Copyright 2017 Frédéric Guillot. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package model // import "miniflux.app/model"
// HomePages returns the list of available home pages.
func HomePages() map[string]string {
return map[string]string{
"unread": "menu.unread",
"starred": "menu.starred",
"history": "menu.history",
"feeds": "menu.feeds",
"categories": "menu.categories",
}
}

View file

@ -32,6 +32,7 @@ type User struct {
DisplayMode string `json:"display_mode"` DisplayMode string `json:"display_mode"`
DefaultReadingSpeed int `json:"default_reading_speed"` DefaultReadingSpeed int `json:"default_reading_speed"`
CJKReadingSpeed int `json:"cjk_reading_speed"` CJKReadingSpeed int `json:"cjk_reading_speed"`
DefaultHomePage string `json:"default_home_page"`
} }
// UserCreationRequest represents the request to create a user. // UserCreationRequest represents the request to create a user.
@ -63,6 +64,7 @@ type UserModificationRequest struct {
DisplayMode *string `json:"display_mode"` DisplayMode *string `json:"display_mode"`
DefaultReadingSpeed *int `json:"default_reading_speed"` DefaultReadingSpeed *int `json:"default_reading_speed"`
CJKReadingSpeed *int `json:"cjk_reading_speed"` CJKReadingSpeed *int `json:"cjk_reading_speed"`
DefaultHomePage *string `json:"default_home_page"`
} }
// Patch updates the User object with the modification request. // Patch updates the User object with the modification request.
@ -138,6 +140,10 @@ func (u *UserModificationRequest) Patch(user *User) {
if u.CJKReadingSpeed != nil { if u.CJKReadingSpeed != nil {
user.CJKReadingSpeed = *u.CJKReadingSpeed user.CJKReadingSpeed = *u.CJKReadingSpeed
} }
if u.DefaultHomePage != nil {
user.DefaultHomePage = *u.DefaultHomePage
}
} }
// UseTimezone converts last login date to the given timezone. // UseTimezone converts last login date to the given timezone.

View file

@ -87,7 +87,8 @@ func (s *Storage) CreateUser(userCreationRequest *model.UserCreationRequest) (*m
display_mode, display_mode,
entry_order, entry_order,
default_reading_speed, default_reading_speed,
cjk_reading_speed cjk_reading_speed,
default_home_page
` `
tx, err := s.db.Begin() tx, err := s.db.Begin()
@ -122,6 +123,7 @@ func (s *Storage) CreateUser(userCreationRequest *model.UserCreationRequest) (*m
&user.EntryOrder, &user.EntryOrder,
&user.DefaultReadingSpeed, &user.DefaultReadingSpeed,
&user.CJKReadingSpeed, &user.CJKReadingSpeed,
&user.DefaultHomePage,
) )
if err != nil { if err != nil {
tx.Rollback() tx.Rollback()
@ -174,9 +176,10 @@ func (s *Storage) UpdateUser(user *model.User) error {
display_mode=$15, display_mode=$15,
entry_order=$16, entry_order=$16,
default_reading_speed=$17, default_reading_speed=$17,
cjk_reading_speed=$18 cjk_reading_speed=$18,
default_home_page=$19
WHERE WHERE
id=$19 id=$20
` `
_, err = s.db.Exec( _, err = s.db.Exec(
@ -199,6 +202,7 @@ func (s *Storage) UpdateUser(user *model.User) error {
user.EntryOrder, user.EntryOrder,
user.DefaultReadingSpeed, user.DefaultReadingSpeed,
user.CJKReadingSpeed, user.CJKReadingSpeed,
user.DefaultHomePage,
user.ID, user.ID,
) )
if err != nil { if err != nil {
@ -223,9 +227,10 @@ func (s *Storage) UpdateUser(user *model.User) error {
display_mode=$14, display_mode=$14,
entry_order=$15, entry_order=$15,
default_reading_speed=$16, default_reading_speed=$16,
cjk_reading_speed=$17 cjk_reading_speed=$17,
default_home_page=$18
WHERE WHERE
id=$18 id=$19
` `
_, err := s.db.Exec( _, err := s.db.Exec(
@ -247,6 +252,7 @@ func (s *Storage) UpdateUser(user *model.User) error {
user.EntryOrder, user.EntryOrder,
user.DefaultReadingSpeed, user.DefaultReadingSpeed,
user.CJKReadingSpeed, user.CJKReadingSpeed,
user.DefaultHomePage,
user.ID, user.ID,
) )
@ -290,7 +296,8 @@ func (s *Storage) UserByID(userID int64) (*model.User, error) {
display_mode, display_mode,
entry_order, entry_order,
default_reading_speed, default_reading_speed,
cjk_reading_speed cjk_reading_speed,
default_home_page
FROM FROM
users users
WHERE WHERE
@ -321,7 +328,8 @@ func (s *Storage) UserByUsername(username string) (*model.User, error) {
display_mode, display_mode,
entry_order, entry_order,
default_reading_speed, default_reading_speed,
cjk_reading_speed cjk_reading_speed,
default_home_page
FROM FROM
users users
WHERE WHERE
@ -352,7 +360,8 @@ func (s *Storage) UserByField(field, value string) (*model.User, error) {
display_mode, display_mode,
entry_order, entry_order,
default_reading_speed, default_reading_speed,
cjk_reading_speed cjk_reading_speed,
default_home_page
FROM FROM
users users
WHERE WHERE
@ -390,7 +399,8 @@ func (s *Storage) UserByAPIKey(token string) (*model.User, error) {
u.display_mode, u.display_mode,
u.entry_order, u.entry_order,
u.default_reading_speed, u.default_reading_speed,
u.cjk_reading_speed u.cjk_reading_speed,
u.default_home_page
FROM FROM
users u users u
LEFT JOIN LEFT JOIN
@ -423,6 +433,7 @@ func (s *Storage) fetchUser(query string, args ...interface{}) (*model.User, err
&user.EntryOrder, &user.EntryOrder,
&user.DefaultReadingSpeed, &user.DefaultReadingSpeed,
&user.CJKReadingSpeed, &user.CJKReadingSpeed,
&user.DefaultHomePage,
) )
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
@ -516,7 +527,8 @@ func (s *Storage) Users() (model.Users, error) {
display_mode, display_mode,
entry_order, entry_order,
default_reading_speed, default_reading_speed,
cjk_reading_speed cjk_reading_speed,
default_home_page
FROM FROM
users users
ORDER BY username ASC ORDER BY username ASC
@ -550,6 +562,7 @@ func (s *Storage) Users() (model.Users, error) {
&user.EntryOrder, &user.EntryOrder,
&user.DefaultReadingSpeed, &user.DefaultReadingSpeed,
&user.CJKReadingSpeed, &user.CJKReadingSpeed,
&user.DefaultHomePage,
) )
if err != nil { if err != nil {

View file

@ -56,7 +56,7 @@
<header class="header"> <header class="header">
<nav> <nav>
<div class="logo"> <div class="logo">
<a href="{{ route "unread" }}">Mini<span>flux</span></a> <a href="{{ route .user.DefaultHomePage }}">Mini<span>flux</span></a>
</div> </div>
<ul> <ul>
<li {{ if eq .menu "unread" }}class="active"{{ end }} title="{{ t "tooltip.keyboard_shortcuts" "g u" }}"> <li {{ if eq .menu "unread" }}class="active"{{ end }} title="{{ t "tooltip.keyboard_shortcuts" "g u" }}">

View file

@ -63,6 +63,13 @@
<option value="created_at" {{ if eq "created_at" $.form.EntryOrder }}selected="selected"{{ end }}>{{ t "form.prefs.select.created_time" }}</option> <option value="created_at" {{ if eq "created_at" $.form.EntryOrder }}selected="selected"{{ end }}>{{ t "form.prefs.select.created_time" }}</option>
</select> </select>
<label for="form-default-home-page">{{ t "form.prefs.label.default_home_page" }}</label>
<select id="form-default-home-page" name="default_home_page">
{{ range $key, $value := .default_home_pages }}
<option value="{{ $key }}" {{ if eq $key $.form.DefaultHomePage }}selected="selected"{{ end }}>{{ t $value }}</option>
{{ end }}
</select>
<label for="form-entries-per-page">{{ t "form.prefs.label.entries_per_page" }}</label> <label for="form-entries-per-page">{{ t "form.prefs.label.entries_per_page" }}</label>
<input type="number" name="entries_per_page" id="form-entries-per-page" value="{{ .form.EntriesPerPage }}" min="1"> <input type="number" name="entries_per_page" id="form-entries-per-page" value="{{ .form.EntriesPerPage }}" min="1">

View file

@ -30,6 +30,7 @@ type SettingsForm struct {
DisplayMode string DisplayMode string
DefaultReadingSpeed int DefaultReadingSpeed int
CJKReadingSpeed int CJKReadingSpeed int
DefaultHomePage string
} }
// Merge updates the fields of the given user. // Merge updates the fields of the given user.
@ -48,6 +49,7 @@ func (s *SettingsForm) Merge(user *model.User) *model.User {
user.DisplayMode = s.DisplayMode user.DisplayMode = s.DisplayMode
user.CJKReadingSpeed = s.CJKReadingSpeed user.CJKReadingSpeed = s.CJKReadingSpeed
user.DefaultReadingSpeed = s.DefaultReadingSpeed user.DefaultReadingSpeed = s.DefaultReadingSpeed
user.DefaultHomePage = s.DefaultHomePage
if s.Password != "" { if s.Password != "" {
user.Password = s.Password user.Password = s.Password
@ -58,7 +60,7 @@ func (s *SettingsForm) Merge(user *model.User) *model.User {
// Validate makes sure the form values are valid. // Validate makes sure the form values are valid.
func (s *SettingsForm) Validate() error { func (s *SettingsForm) Validate() error {
if s.Username == "" || s.Theme == "" || s.Language == "" || s.Timezone == "" || s.EntryDirection == "" || s.DisplayMode == "" { if s.Username == "" || s.Theme == "" || s.Language == "" || s.Timezone == "" || s.EntryDirection == "" || s.DisplayMode == "" || s.DefaultHomePage == "" {
return errors.NewLocalizedError("error.settings_mandatory_fields") return errors.NewLocalizedError("error.settings_mandatory_fields")
} }
@ -111,5 +113,6 @@ func NewSettingsForm(r *http.Request) *SettingsForm {
DisplayMode: r.FormValue("display_mode"), DisplayMode: r.FormValue("display_mode"),
DefaultReadingSpeed: int(defaultReadingSpeed), DefaultReadingSpeed: int(defaultReadingSpeed),
CJKReadingSpeed: int(cjkReadingSpeed), CJKReadingSpeed: int(cjkReadingSpeed),
DefaultHomePage: r.FormValue("default_home_page"),
} }
} }

View file

@ -17,6 +17,7 @@ func TestValid(t *testing.T) {
DisplayMode: "standalone", DisplayMode: "standalone",
DefaultReadingSpeed: 35, DefaultReadingSpeed: 35,
CJKReadingSpeed: 25, CJKReadingSpeed: 25,
DefaultHomePage: "unread",
} }
err := settings.Validate() err := settings.Validate()
@ -38,6 +39,7 @@ func TestConfirmationEmpty(t *testing.T) {
DisplayMode: "standalone", DisplayMode: "standalone",
DefaultReadingSpeed: 35, DefaultReadingSpeed: 35,
CJKReadingSpeed: 25, CJKReadingSpeed: 25,
DefaultHomePage: "unread",
} }
err := settings.Validate() err := settings.Validate()
@ -63,6 +65,7 @@ func TestConfirmationIncorrect(t *testing.T) {
DisplayMode: "standalone", DisplayMode: "standalone",
DefaultReadingSpeed: 35, DefaultReadingSpeed: 35,
CJKReadingSpeed: 25, CJKReadingSpeed: 25,
DefaultHomePage: "unread",
} }
err := settings.Validate() err := settings.Validate()

View file

@ -60,5 +60,5 @@ func (h *handler) checkLogin(w http.ResponseWriter, r *http.Request) {
config.Opts.BasePath(), config.Opts.BasePath(),
)) ))
html.Redirect(w, r, route.Path(h.router, "unread")) html.Redirect(w, r, route.Path(h.router, user.DefaultHomePage))
} }

View file

@ -16,7 +16,13 @@ import (
func (h *handler) showLoginPage(w http.ResponseWriter, r *http.Request) { func (h *handler) showLoginPage(w http.ResponseWriter, r *http.Request) {
if request.IsAuthenticated(r) { if request.IsAuthenticated(r) {
html.Redirect(w, r, route.Path(h.router, "unread")) user, err := h.store.UserByID(request.UserID(r))
if err != nil {
html.ServerError(w, r, err)
return
}
html.Redirect(w, r, route.Path(h.router, user.DefaultHomePage))
return return
} }

View file

@ -41,6 +41,7 @@ func (h *handler) showSettingsPage(w http.ResponseWriter, r *http.Request) {
DisplayMode: user.DisplayMode, DisplayMode: user.DisplayMode,
DefaultReadingSpeed: user.DefaultReadingSpeed, DefaultReadingSpeed: user.DefaultReadingSpeed,
CJKReadingSpeed: user.CJKReadingSpeed, CJKReadingSpeed: user.CJKReadingSpeed,
DefaultHomePage: user.DefaultHomePage,
} }
timezones, err := h.store.Timezones() timezones, err := h.store.Timezones()
@ -57,6 +58,7 @@ func (h *handler) showSettingsPage(w http.ResponseWriter, r *http.Request) {
view.Set("user", user) view.Set("user", user)
view.Set("countUnread", h.store.CountUnreadEntries(user.ID)) view.Set("countUnread", h.store.CountUnreadEntries(user.ID))
view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(user.ID)) view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(user.ID))
view.Set("default_home_pages", model.HomePages())
html.OK(w, r, view.Render("settings")) html.OK(w, r, view.Render("settings"))
} }

View file

@ -63,6 +63,7 @@ func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) {
DisplayMode: model.OptionalString(settingsForm.DisplayMode), DisplayMode: model.OptionalString(settingsForm.DisplayMode),
DefaultReadingSpeed: model.OptionalInt(settingsForm.DefaultReadingSpeed), DefaultReadingSpeed: model.OptionalInt(settingsForm.DefaultReadingSpeed),
CJKReadingSpeed: model.OptionalInt(settingsForm.CJKReadingSpeed), CJKReadingSpeed: model.OptionalInt(settingsForm.CJKReadingSpeed),
DefaultHomePage: model.OptionalString(settingsForm.DefaultHomePage),
} }
if validationErr := validator.ValidateUserModification(h.store, loggedUser.ID, userModificationRequest); validationErr != nil { if validationErr := validator.ValidateUserModification(h.store, loggedUser.ID, userModificationRequest); validationErr != nil {

View file

@ -91,6 +91,12 @@ func ValidateUserModification(store *storage.Storage, userID int64, changes *mod
} }
} }
if changes.DefaultHomePage != nil {
if err := validateDefaultHomePage(*changes.DefaultHomePage); err != nil {
return err
}
}
return nil return nil
} }
@ -156,3 +162,11 @@ func validateDisplayMode(displayMode string) *ValidationError {
} }
return nil return nil
} }
func validateDefaultHomePage(defaultHomePage string) *ValidationError {
defaultHomePages := model.HomePages()
if _, found := defaultHomePages[defaultHomePage]; !found {
return NewValidationError("error.invalid_default_home_page")
}
return nil
}