Make default home page configurable
This commit is contained in:
parent
45a9fd5af6
commit
03a1cfcd5e
30 changed files with 125 additions and 14 deletions
|
@ -38,6 +38,7 @@ type User struct {
|
|||
DisplayMode string `json:"display_mode"`
|
||||
DefaultReadingSpeed int `json:"default_reading_speed"`
|
||||
CJKReadingSpeed int `json:"cjk_reading_speed"`
|
||||
DefaultHomePage string `json:"default_home_page"`
|
||||
}
|
||||
|
||||
func (u User) String() string {
|
||||
|
@ -73,6 +74,7 @@ type UserModificationRequest struct {
|
|||
DisplayMode *string `json:"display_mode"`
|
||||
DefaultReadingSpeed *int `json:"default_reading_speed"`
|
||||
CJKReadingSpeed *int `json:"cjk_reading_speed"`
|
||||
DefaultHomePage *string `json:"default_home_page"`
|
||||
}
|
||||
|
||||
// Users represents a list of users.
|
||||
|
|
|
@ -604,4 +604,10 @@ var migrations = []func(tx *sql.Tx) error{
|
|||
`)
|
||||
return
|
||||
},
|
||||
func(tx *sql.Tx) (err error) {
|
||||
_, err = tx.Exec(`
|
||||
ALTER TABLE users ADD COLUMN default_home_page text default 'unread';
|
||||
`)
|
||||
return
|
||||
},
|
||||
}
|
||||
|
|
|
@ -263,6 +263,7 @@
|
|||
"error.invalid_timezone": "Ungültige Zeitzone.",
|
||||
"error.invalid_entry_direction": "Ungültige Sortierreihenfolge.",
|
||||
"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.site_url": "Webseite-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.custom_css": "Benutzerdefiniertes CSS",
|
||||
"form.prefs.label.entry_order": "Eintrag Sortierspalte",
|
||||
"form.prefs.label.default_home_page": "Standard Startseite",
|
||||
"form.import.label.file": "OPML Datei",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Fever API aktivieren",
|
||||
|
|
|
@ -241,6 +241,7 @@
|
|||
"error.invalid_timezone": "Μη έγκυρη ζώνη ώρας.",
|
||||
"error.invalid_entry_direction": "Μη έγκυρη κατεύθυνση ταξινόμησης άρθρων.",
|
||||
"error.invalid_display_mode": "Μη έγκυρη λειτουργία εμφάνισης εφαρμογών ιστού.",
|
||||
"error.invalid_default_home_page": "Μη έγκυρη προεπιλεγμένη αρχική σελίδα!",
|
||||
"error.empty_file": "Αυτό το αρχείο είναι κενό.",
|
||||
"error.bad_credentials": "Μη έγκυρο όνομα χρήστη ή κωδικό πρόσβασης.",
|
||||
"error.fields_mandatory": "Όλα τα πεδία είναι υποχρεωτικά.",
|
||||
|
@ -309,6 +310,7 @@
|
|||
"form.prefs.label.show_reading_time": "Εμφάνιση εκτιμώμενου χρόνου ανάγνωσης για άρθρα",
|
||||
"form.prefs.label.custom_css": "Προσαρμοσμένο CSS",
|
||||
"form.prefs.label.entry_order": "Στήλη ταξινόμησης εισόδου",
|
||||
"form.prefs.label.default_home_page": "Προεπιλεγμένη αρχική σελίδα",
|
||||
"form.import.label.file": "Αρχείο OPML",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Ενεργοποιήστε το Fever API",
|
||||
|
|
|
@ -241,6 +241,7 @@
|
|||
"error.invalid_timezone": "Invalid timezone.",
|
||||
"error.invalid_entry_direction": "Invalid entry direction.",
|
||||
"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.bad_credentials": "Invalid username or password.",
|
||||
"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.custom_css": "Custom CSS",
|
||||
"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.url": "URL",
|
||||
"form.integration.fever_activate": "Activate Fever API",
|
||||
|
|
|
@ -263,6 +263,7 @@
|
|||
"error.invalid_timezone": "Zona horaria 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_default_home_page": "¡Página de inicio por defecto inválida!",
|
||||
"form.feed.label.title": "Título",
|
||||
"form.feed.label.site_url": "URL del sitio",
|
||||
"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.custom_css": "CSS personalizado",
|
||||
"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.url": "URL",
|
||||
"form.integration.fever_activate": "Activar API de Fever",
|
||||
|
|
|
@ -241,6 +241,7 @@
|
|||
"error.invalid_timezone": "Virheellinen aikavyöhyke.",
|
||||
"error.invalid_entry_direction": "Invalid entry direction.",
|
||||
"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.bad_credentials": "Virheellinen käyttäjänimi tai salasana.",
|
||||
"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.custom_css": "Mukautettu CSS",
|
||||
"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.url": "URL",
|
||||
"form.integration.fever_activate": "Ota Fever API käyttöön",
|
||||
|
|
|
@ -263,6 +263,7 @@
|
|||
"error.invalid_timezone": "Fuseau horaire 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_default_home_page": "Page d'accueil par défaut invalide !",
|
||||
"form.feed.label.title": "Titre",
|
||||
"form.feed.label.site_url": "URL du site web",
|
||||
"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.custom_css": "CSS personnalisé",
|
||||
"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.url": "URL",
|
||||
"form.integration.fever_activate": "Activer l'API de Fever",
|
||||
|
|
|
@ -241,6 +241,7 @@
|
|||
"error.invalid_timezone": "अमान्य समयक्षेत्र.",
|
||||
"error.invalid_entry_direction": "अमान्य प्रवेश दिशा।",
|
||||
"error.invalid_display_mode": "अमान्य वेब ऐप्लिकेशन प्रदर्शन मोड.",
|
||||
"error.invalid_default_home_page": "अमान्य डिफ़ॉल्ट मुखपृष्ठ!",
|
||||
"error.empty_file": "यह फ़ाइल खाली है।",
|
||||
"error.bad_credentials": "अमान्य उपयोगकर्ता नाम या पासवर्ड।",
|
||||
"error.fields_mandatory": "सभी फील्ड अनिवार्य।",
|
||||
|
@ -309,6 +310,7 @@
|
|||
"form.prefs.label.show_reading_time": "विषय के लिए अनुमानित पढ़ने का समय दिखाएं",
|
||||
"form.prefs.label.custom_css": "कस्टम सीएसएस",
|
||||
"form.prefs.label.entry_order": "प्रवेश छँटाई कॉलम",
|
||||
"form.prefs.label.default_home_page": "डिफ़ॉल्ट होमपेज़",
|
||||
"form.import.label.file": "ओपीएमएल फ़ाइल",
|
||||
"form.import.label.url": "यूआरएल",
|
||||
"form.integration.fever_activate": "फीवर एपीआई सक्रिय करें",
|
||||
|
|
|
@ -263,6 +263,7 @@
|
|||
"error.invalid_timezone": "Fuso orario non valido.",
|
||||
"error.invalid_entry_direction": "Ordinamento non valido.",
|
||||
"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.site_url": "URL del sito",
|
||||
"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.custom_css": "CSS personalizzati",
|
||||
"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.url": "URL",
|
||||
"form.integration.fever_activate": "Abilita l'API di Fever",
|
||||
|
|
|
@ -263,6 +263,7 @@
|
|||
"error.invalid_timezone": "タイムゾーンが無効です。",
|
||||
"error.invalid_entry_direction": "ソート順が無効です。",
|
||||
"error.invalid_display_mode": "Webアプリの表示モードが無効です。",
|
||||
"error.invalid_default_home_page": "デフォルトのホームページが無効です",
|
||||
"form.feed.label.title": "タイトル",
|
||||
"form.feed.label.site_url": "サイト URL",
|
||||
"form.feed.label.feed_url": "フィード URL",
|
||||
|
@ -309,6 +310,7 @@
|
|||
"form.prefs.label.show_reading_time": "記事の推定読書時間を表示する",
|
||||
"form.prefs.label.custom_css": "カスタムCSS",
|
||||
"form.prefs.label.entry_order": "エントリーソートカラム",
|
||||
"form.prefs.label.default_home_page": "デフォルトのトップページ",
|
||||
"form.import.label.file": "OPML ファイル",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Fever API を有効にする",
|
||||
|
|
|
@ -263,6 +263,7 @@
|
|||
"error.invalid_timezone": "Ongeldige tijdzone.",
|
||||
"error.invalid_entry_direction": "Ongeldige sorteervolgorde.",
|
||||
"error.invalid_display_mode": "Ongeldige weergavemodus voor webapp.",
|
||||
"error.invalid_default_home_page": "Ongeldige standaard homepage!",
|
||||
"form.feed.label.title": "Naam",
|
||||
"form.feed.label.site_url": "Website 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.custom_css": "Aangepaste CSS",
|
||||
"form.prefs.label.entry_order": "Ingang Sorteerkolom",
|
||||
"form.prefs.label.default_home_page": "Standaard startpagina",
|
||||
"form.import.label.file": "OPML-bestand",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Activeer Fever API",
|
||||
|
|
|
@ -265,6 +265,7 @@
|
|||
"error.invalid_timezone": "Nieprawidłowa strefa czasowa.",
|
||||
"error.invalid_entry_direction": "Nieprawidłowa kolejność sortowania.",
|
||||
"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.site_url": "URL strony",
|
||||
"form.feed.label.feed_url": "URL kanału",
|
||||
|
@ -311,6 +312,7 @@
|
|||
"form.prefs.select.created_time": "Czas utworzenia wpisu",
|
||||
"form.prefs.label.custom_css": "Niestandardowy CSS",
|
||||
"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.url": "URL",
|
||||
"form.integration.fever_activate": "Aktywuj Fever API",
|
||||
|
|
|
@ -263,6 +263,7 @@
|
|||
"error.invalid_timezone": "Fuso horário inválido.",
|
||||
"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_default_home_page": "Página inicial por defeito inválida!",
|
||||
"form.feed.label.title": "Título",
|
||||
"form.feed.label.site_url": "URL do site",
|
||||
"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.custom_css": "CSS customizado",
|
||||
"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.url": "URL",
|
||||
"form.integration.fever_activate": "Ativar API do Fever",
|
||||
|
|
|
@ -265,6 +265,7 @@
|
|||
"error.invalid_timezone": "Неверный часовой пояс.",
|
||||
"error.invalid_entry_direction": "Неверное направление входа.",
|
||||
"error.invalid_display_mode": "Недопустимый режим отображения веб-приложения.",
|
||||
"error.invalid_default_home_page": "Неверная домашняя страница по умолчанию!",
|
||||
"form.feed.label.title": "Название",
|
||||
"form.feed.label.site_url": "URL сайта",
|
||||
"form.feed.label.feed_url": "URL подписки",
|
||||
|
@ -311,6 +312,7 @@
|
|||
"form.prefs.label.show_reading_time": "Показать примерное время чтения статей",
|
||||
"form.prefs.label.custom_css": "Пользовательские CSS",
|
||||
"form.prefs.label.entry_order": "Колонка сортировки ввода",
|
||||
"form.prefs.label.default_home_page": "Домашняя страница по умолчанию",
|
||||
"form.import.label.file": "OPML файл",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "Активировать Fever API",
|
||||
|
|
|
@ -241,6 +241,7 @@
|
|||
"error.invalid_timezone": "Geçersiz saat dilimi",
|
||||
"error.invalid_entry_direction": "Geçersiz giriş yönü.",
|
||||
"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.bad_credentials": "Geçersiz kullanıcı veya parola.",
|
||||
"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.custom_css": "Özel CSS",
|
||||
"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.url": "URL",
|
||||
"form.integration.fever_activate": "Fever API'yi Etkinleştir",
|
||||
|
|
|
@ -261,6 +261,7 @@
|
|||
"error.invalid_timezone": "无效的时区。",
|
||||
"error.invalid_entry_direction": "无效的输入方向。",
|
||||
"error.invalid_display_mode": "无效的网页应用显示模式。",
|
||||
"error.invalid_default_home_page": "无效的默认主页!",
|
||||
"form.feed.label.title": "标题",
|
||||
"form.feed.label.site_url": "源网站 URL",
|
||||
"form.feed.label.feed_url": "订阅源 URL",
|
||||
|
@ -307,6 +308,7 @@
|
|||
"form.prefs.label.show_reading_time": "显示文章的预计阅读时间",
|
||||
"form.prefs.label.custom_css": "自定义 CSS",
|
||||
"form.prefs.label.entry_order": "文章排序依据",
|
||||
"form.prefs.label.default_home_page": "默认主页",
|
||||
"form.import.label.file": "OPML 文件",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "启用 Fever API",
|
||||
|
|
|
@ -263,6 +263,7 @@
|
|||
"error.invalid_timezone": "無效的時區。",
|
||||
"error.invalid_entry_direction": "無效的輸入方向。",
|
||||
"error.invalid_display_mode": "無效的網頁應用顯示模式。",
|
||||
"error.invalid_default_home_page": "默認主頁無效!",
|
||||
"form.feed.label.title": "標題",
|
||||
"form.feed.label.site_url": "網站 URL",
|
||||
"form.feed.label.feed_url": "訂閱Feed URL",
|
||||
|
@ -309,6 +310,7 @@
|
|||
"form.prefs.label.show_reading_time": "顯示文章的預計閱讀時間",
|
||||
"form.prefs.label.custom_css": "自定義 CSS",
|
||||
"form.prefs.label.entry_order": "文章排序依據",
|
||||
"form.prefs.label.default_home_page": "默認主頁",
|
||||
"form.import.label.file": "OPML 檔案",
|
||||
"form.import.label.url": "URL",
|
||||
"form.integration.fever_activate": "啟用 Fever API",
|
||||
|
|
16
model/home_page.go
Normal file
16
model/home_page.go
Normal 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",
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ type User struct {
|
|||
DisplayMode string `json:"display_mode"`
|
||||
DefaultReadingSpeed int `json:"default_reading_speed"`
|
||||
CJKReadingSpeed int `json:"cjk_reading_speed"`
|
||||
DefaultHomePage string `json:"default_home_page"`
|
||||
}
|
||||
|
||||
// UserCreationRequest represents the request to create a user.
|
||||
|
@ -63,6 +64,7 @@ type UserModificationRequest struct {
|
|||
DisplayMode *string `json:"display_mode"`
|
||||
DefaultReadingSpeed *int `json:"default_reading_speed"`
|
||||
CJKReadingSpeed *int `json:"cjk_reading_speed"`
|
||||
DefaultHomePage *string `json:"default_home_page"`
|
||||
}
|
||||
|
||||
// Patch updates the User object with the modification request.
|
||||
|
@ -138,6 +140,10 @@ func (u *UserModificationRequest) Patch(user *User) {
|
|||
if u.CJKReadingSpeed != nil {
|
||||
user.CJKReadingSpeed = *u.CJKReadingSpeed
|
||||
}
|
||||
|
||||
if u.DefaultHomePage != nil {
|
||||
user.DefaultHomePage = *u.DefaultHomePage
|
||||
}
|
||||
}
|
||||
|
||||
// UseTimezone converts last login date to the given timezone.
|
||||
|
|
|
@ -87,7 +87,8 @@ func (s *Storage) CreateUser(userCreationRequest *model.UserCreationRequest) (*m
|
|||
display_mode,
|
||||
entry_order,
|
||||
default_reading_speed,
|
||||
cjk_reading_speed
|
||||
cjk_reading_speed,
|
||||
default_home_page
|
||||
`
|
||||
|
||||
tx, err := s.db.Begin()
|
||||
|
@ -122,6 +123,7 @@ func (s *Storage) CreateUser(userCreationRequest *model.UserCreationRequest) (*m
|
|||
&user.EntryOrder,
|
||||
&user.DefaultReadingSpeed,
|
||||
&user.CJKReadingSpeed,
|
||||
&user.DefaultHomePage,
|
||||
)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
|
@ -174,9 +176,10 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
|||
display_mode=$15,
|
||||
entry_order=$16,
|
||||
default_reading_speed=$17,
|
||||
cjk_reading_speed=$18
|
||||
cjk_reading_speed=$18,
|
||||
default_home_page=$19
|
||||
WHERE
|
||||
id=$19
|
||||
id=$20
|
||||
`
|
||||
|
||||
_, err = s.db.Exec(
|
||||
|
@ -199,6 +202,7 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
|||
user.EntryOrder,
|
||||
user.DefaultReadingSpeed,
|
||||
user.CJKReadingSpeed,
|
||||
user.DefaultHomePage,
|
||||
user.ID,
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -223,9 +227,10 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
|||
display_mode=$14,
|
||||
entry_order=$15,
|
||||
default_reading_speed=$16,
|
||||
cjk_reading_speed=$17
|
||||
cjk_reading_speed=$17,
|
||||
default_home_page=$18
|
||||
WHERE
|
||||
id=$18
|
||||
id=$19
|
||||
`
|
||||
|
||||
_, err := s.db.Exec(
|
||||
|
@ -247,6 +252,7 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
|||
user.EntryOrder,
|
||||
user.DefaultReadingSpeed,
|
||||
user.CJKReadingSpeed,
|
||||
user.DefaultHomePage,
|
||||
user.ID,
|
||||
)
|
||||
|
||||
|
@ -290,7 +296,8 @@ func (s *Storage) UserByID(userID int64) (*model.User, error) {
|
|||
display_mode,
|
||||
entry_order,
|
||||
default_reading_speed,
|
||||
cjk_reading_speed
|
||||
cjk_reading_speed,
|
||||
default_home_page
|
||||
FROM
|
||||
users
|
||||
WHERE
|
||||
|
@ -321,7 +328,8 @@ func (s *Storage) UserByUsername(username string) (*model.User, error) {
|
|||
display_mode,
|
||||
entry_order,
|
||||
default_reading_speed,
|
||||
cjk_reading_speed
|
||||
cjk_reading_speed,
|
||||
default_home_page
|
||||
FROM
|
||||
users
|
||||
WHERE
|
||||
|
@ -352,7 +360,8 @@ func (s *Storage) UserByField(field, value string) (*model.User, error) {
|
|||
display_mode,
|
||||
entry_order,
|
||||
default_reading_speed,
|
||||
cjk_reading_speed
|
||||
cjk_reading_speed,
|
||||
default_home_page
|
||||
FROM
|
||||
users
|
||||
WHERE
|
||||
|
@ -390,7 +399,8 @@ func (s *Storage) UserByAPIKey(token string) (*model.User, error) {
|
|||
u.display_mode,
|
||||
u.entry_order,
|
||||
u.default_reading_speed,
|
||||
u.cjk_reading_speed
|
||||
u.cjk_reading_speed,
|
||||
u.default_home_page
|
||||
FROM
|
||||
users u
|
||||
LEFT JOIN
|
||||
|
@ -423,6 +433,7 @@ func (s *Storage) fetchUser(query string, args ...interface{}) (*model.User, err
|
|||
&user.EntryOrder,
|
||||
&user.DefaultReadingSpeed,
|
||||
&user.CJKReadingSpeed,
|
||||
&user.DefaultHomePage,
|
||||
)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
|
@ -516,7 +527,8 @@ func (s *Storage) Users() (model.Users, error) {
|
|||
display_mode,
|
||||
entry_order,
|
||||
default_reading_speed,
|
||||
cjk_reading_speed
|
||||
cjk_reading_speed,
|
||||
default_home_page
|
||||
FROM
|
||||
users
|
||||
ORDER BY username ASC
|
||||
|
@ -550,6 +562,7 @@ func (s *Storage) Users() (model.Users, error) {
|
|||
&user.EntryOrder,
|
||||
&user.DefaultReadingSpeed,
|
||||
&user.CJKReadingSpeed,
|
||||
&user.DefaultHomePage,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
<header class="header">
|
||||
<nav>
|
||||
<div class="logo">
|
||||
<a href="{{ route "unread" }}">Mini<span>flux</span></a>
|
||||
<a href="{{ route .user.DefaultHomePage }}">Mini<span>flux</span></a>
|
||||
</div>
|
||||
<ul>
|
||||
<li {{ if eq .menu "unread" }}class="active"{{ end }} title="{{ t "tooltip.keyboard_shortcuts" "g u" }}">
|
||||
|
|
|
@ -63,6 +63,13 @@
|
|||
<option value="created_at" {{ if eq "created_at" $.form.EntryOrder }}selected="selected"{{ end }}>{{ t "form.prefs.select.created_time" }}</option>
|
||||
</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>
|
||||
<input type="number" name="entries_per_page" id="form-entries-per-page" value="{{ .form.EntriesPerPage }}" min="1">
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ type SettingsForm struct {
|
|||
DisplayMode string
|
||||
DefaultReadingSpeed int
|
||||
CJKReadingSpeed int
|
||||
DefaultHomePage string
|
||||
}
|
||||
|
||||
// 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.CJKReadingSpeed = s.CJKReadingSpeed
|
||||
user.DefaultReadingSpeed = s.DefaultReadingSpeed
|
||||
user.DefaultHomePage = s.DefaultHomePage
|
||||
|
||||
if 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.
|
||||
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")
|
||||
}
|
||||
|
||||
|
@ -111,5 +113,6 @@ func NewSettingsForm(r *http.Request) *SettingsForm {
|
|||
DisplayMode: r.FormValue("display_mode"),
|
||||
DefaultReadingSpeed: int(defaultReadingSpeed),
|
||||
CJKReadingSpeed: int(cjkReadingSpeed),
|
||||
DefaultHomePage: r.FormValue("default_home_page"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ func TestValid(t *testing.T) {
|
|||
DisplayMode: "standalone",
|
||||
DefaultReadingSpeed: 35,
|
||||
CJKReadingSpeed: 25,
|
||||
DefaultHomePage: "unread",
|
||||
}
|
||||
|
||||
err := settings.Validate()
|
||||
|
@ -38,6 +39,7 @@ func TestConfirmationEmpty(t *testing.T) {
|
|||
DisplayMode: "standalone",
|
||||
DefaultReadingSpeed: 35,
|
||||
CJKReadingSpeed: 25,
|
||||
DefaultHomePage: "unread",
|
||||
}
|
||||
|
||||
err := settings.Validate()
|
||||
|
@ -63,6 +65,7 @@ func TestConfirmationIncorrect(t *testing.T) {
|
|||
DisplayMode: "standalone",
|
||||
DefaultReadingSpeed: 35,
|
||||
CJKReadingSpeed: 25,
|
||||
DefaultHomePage: "unread",
|
||||
}
|
||||
|
||||
err := settings.Validate()
|
||||
|
|
|
@ -60,5 +60,5 @@ func (h *handler) checkLogin(w http.ResponseWriter, r *http.Request) {
|
|||
config.Opts.BasePath(),
|
||||
))
|
||||
|
||||
html.Redirect(w, r, route.Path(h.router, "unread"))
|
||||
html.Redirect(w, r, route.Path(h.router, user.DefaultHomePage))
|
||||
}
|
||||
|
|
|
@ -16,7 +16,13 @@ import (
|
|||
|
||||
func (h *handler) showLoginPage(w http.ResponseWriter, r *http.Request) {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ func (h *handler) showSettingsPage(w http.ResponseWriter, r *http.Request) {
|
|||
DisplayMode: user.DisplayMode,
|
||||
DefaultReadingSpeed: user.DefaultReadingSpeed,
|
||||
CJKReadingSpeed: user.CJKReadingSpeed,
|
||||
DefaultHomePage: user.DefaultHomePage,
|
||||
}
|
||||
|
||||
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("countUnread", h.store.CountUnreadEntries(user.ID))
|
||||
view.Set("countErrorFeeds", h.store.CountUserFeedsWithErrors(user.ID))
|
||||
view.Set("default_home_pages", model.HomePages())
|
||||
|
||||
html.OK(w, r, view.Render("settings"))
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) {
|
|||
DisplayMode: model.OptionalString(settingsForm.DisplayMode),
|
||||
DefaultReadingSpeed: model.OptionalInt(settingsForm.DefaultReadingSpeed),
|
||||
CJKReadingSpeed: model.OptionalInt(settingsForm.CJKReadingSpeed),
|
||||
DefaultHomePage: model.OptionalString(settingsForm.DefaultHomePage),
|
||||
}
|
||||
|
||||
if validationErr := validator.ValidateUserModification(h.store, loggedUser.ID, userModificationRequest); validationErr != nil {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -156,3 +162,11 @@ func validateDisplayMode(displayMode string) *ValidationError {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateDefaultHomePage(defaultHomePage string) *ValidationError {
|
||||
defaultHomePages := model.HomePages()
|
||||
if _, found := defaultHomePages[defaultHomePage]; !found {
|
||||
return NewValidationError("error.invalid_default_home_page")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue