mirror of
https://github.com/miniflux/v2.git
synced 2025-06-27 16:36:00 +00:00
feat: add new settings option to allow external fonts
This commit is contained in:
parent
600dea6ce5
commit
e555e442fb
32 changed files with 257 additions and 56 deletions
|
@ -45,6 +45,7 @@ type User struct {
|
||||||
MediaPlaybackRate float64 `json:"media_playback_rate"`
|
MediaPlaybackRate float64 `json:"media_playback_rate"`
|
||||||
BlockFilterEntryRules string `json:"block_filter_entry_rules"`
|
BlockFilterEntryRules string `json:"block_filter_entry_rules"`
|
||||||
KeepFilterEntryRules string `json:"keep_filter_entry_rules"`
|
KeepFilterEntryRules string `json:"keep_filter_entry_rules"`
|
||||||
|
ExternalFontHosts string `json:"external_font_hosts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u User) String() string {
|
func (u User) String() string {
|
||||||
|
@ -88,6 +89,7 @@ type UserModificationRequest struct {
|
||||||
MediaPlaybackRate *float64 `json:"media_playback_rate"`
|
MediaPlaybackRate *float64 `json:"media_playback_rate"`
|
||||||
BlockFilterEntryRules *string `json:"block_filter_entry_rules"`
|
BlockFilterEntryRules *string `json:"block_filter_entry_rules"`
|
||||||
KeepFilterEntryRules *string `json:"keep_filter_entry_rules"`
|
KeepFilterEntryRules *string `json:"keep_filter_entry_rules"`
|
||||||
|
ExternalFontHosts *string `json:"external_font_hosts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Users represents a list of users.
|
// Users represents a list of users.
|
||||||
|
|
|
@ -592,6 +592,59 @@ func TestUpdateUserEndpointByChangingDefaultTheme(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateUserEndpointByChangingExternalFonts(t *testing.T) {
|
||||||
|
testConfig := newIntegrationTestConfig()
|
||||||
|
if !testConfig.isConfigured() {
|
||||||
|
t.Skip(skipIntegrationTestsMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
adminClient := miniflux.NewClient(testConfig.testBaseURL, testConfig.testAdminUsername, testConfig.testAdminPassword)
|
||||||
|
regularTestUser, err := adminClient.CreateUser(testConfig.genRandomUsername(), testConfig.testRegularPassword, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer adminClient.DeleteUser(regularTestUser.ID)
|
||||||
|
|
||||||
|
regularUserClient := miniflux.NewClient(testConfig.testBaseURL, regularTestUser.Username, testConfig.testRegularPassword)
|
||||||
|
|
||||||
|
userUpdateRequest := &miniflux.UserModificationRequest{
|
||||||
|
ExternalFontHosts: miniflux.SetOptionalField(" fonts.example.org "),
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedUser, err := regularUserClient.UpdateUser(regularTestUser.ID, userUpdateRequest)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if updatedUser.ExternalFontHosts != "fonts.example.org" {
|
||||||
|
t.Fatalf(`Invalid external font hosts, got "%v"`, updatedUser.ExternalFontHosts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateUserEndpointByChangingExternalFontsWithInvalidValue(t *testing.T) {
|
||||||
|
testConfig := newIntegrationTestConfig()
|
||||||
|
if !testConfig.isConfigured() {
|
||||||
|
t.Skip(skipIntegrationTestsMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
adminClient := miniflux.NewClient(testConfig.testBaseURL, testConfig.testAdminUsername, testConfig.testAdminPassword)
|
||||||
|
regularTestUser, err := adminClient.CreateUser(testConfig.genRandomUsername(), testConfig.testRegularPassword, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer adminClient.DeleteUser(regularTestUser.ID)
|
||||||
|
|
||||||
|
regularUserClient := miniflux.NewClient(testConfig.testBaseURL, regularTestUser.Username, testConfig.testRegularPassword)
|
||||||
|
|
||||||
|
userUpdateRequest := &miniflux.UserModificationRequest{
|
||||||
|
ExternalFontHosts: miniflux.SetOptionalField("'self' *"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := regularUserClient.UpdateUser(regularTestUser.ID, userUpdateRequest); err == nil {
|
||||||
|
t.Fatal(`Updating the user with an invalid external font host should raise an error`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUpdateUserEndpointByChangingCustomJS(t *testing.T) {
|
func TestUpdateUserEndpointByChangingCustomJS(t *testing.T) {
|
||||||
testConfig := newIntegrationTestConfig()
|
testConfig := newIntegrationTestConfig()
|
||||||
if !testConfig.isConfigured() {
|
if !testConfig.isConfigured() {
|
||||||
|
|
|
@ -947,4 +947,9 @@ var migrations = []func(tx *sql.Tx) error{
|
||||||
_, err = tx.Exec(sql)
|
_, err = tx.Exec(sql)
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
|
func(tx *sql.Tx) (err error) {
|
||||||
|
sql := `ALTER TABLE users ADD COLUMN external_font_hosts text not null default '';`
|
||||||
|
_, err = tx.Exec(sql)
|
||||||
|
return err
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -391,7 +391,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Geste zum Navigieren zwischen Einträgen",
|
"form.prefs.label.gesture_nav": "Geste zum Navigieren zwischen Einträgen",
|
||||||
"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.custom_js": "Benutzerdefiniertes JS",
|
"form.prefs.label.custom_js": "Benutzerdefiniertes JavaScript",
|
||||||
"form.prefs.label.entry_order": "Artikel-Sortierspalte",
|
"form.prefs.label.entry_order": "Artikel-Sortierspalte",
|
||||||
"form.prefs.label.default_home_page": "Standard-Startseite",
|
"form.prefs.label.default_home_page": "Standard-Startseite",
|
||||||
"form.prefs.label.categories_sorting_order": "Kategorie-Sortierung",
|
"form.prefs.label.categories_sorting_order": "Kategorie-Sortierung",
|
||||||
|
@ -403,6 +403,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentifizierungseinstellungen",
|
"form.prefs.fieldset.authentication_settings": "Authentifizierungseinstellungen",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader-Einstellungen",
|
"form.prefs.fieldset.reader_settings": "Reader-Einstellungen",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "Externe Schriftarten-Hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "OPML Datei",
|
"form.import.label.file": "OPML Datei",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -391,7 +391,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Χειρονομία για πλοήγηση μεταξύ των καταχωρήσεων",
|
"form.prefs.label.gesture_nav": "Χειρονομία για πλοήγηση μεταξύ των καταχωρήσεων",
|
||||||
"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.custom_js": "Προσαρμοσμένο JS",
|
"form.prefs.label.custom_js": "Προσαρμοσμένο JavaScript",
|
||||||
"form.prefs.label.entry_order": "Στήλη ταξινόμησης εισόδου",
|
"form.prefs.label.entry_order": "Στήλη ταξινόμησης εισόδου",
|
||||||
"form.prefs.label.default_home_page": "Προεπιλεγμένη αρχική σελίδα",
|
"form.prefs.label.default_home_page": "Προεπιλεγμένη αρχική σελίδα",
|
||||||
"form.prefs.label.categories_sorting_order": "Ταξινόμηση κατηγοριών",
|
"form.prefs.label.categories_sorting_order": "Ταξινόμηση κατηγοριών",
|
||||||
|
@ -403,6 +403,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "Αρχείο OPML",
|
"form.import.label.file": "Αρχείο OPML",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -391,7 +391,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Gesture to navigate between entries",
|
"form.prefs.label.gesture_nav": "Gesture to navigate between entries",
|
||||||
"form.prefs.label.show_reading_time": "Show estimated reading time for entries",
|
"form.prefs.label.show_reading_time": "Show estimated reading time for entries",
|
||||||
"form.prefs.label.custom_css": "Custom CSS",
|
"form.prefs.label.custom_css": "Custom CSS",
|
||||||
"form.prefs.label.custom_js": "Custom JS",
|
"form.prefs.label.custom_js": "Custom JavaScript",
|
||||||
"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.prefs.label.default_home_page": "Default home page",
|
||||||
"form.prefs.label.categories_sorting_order": "Categories sorting",
|
"form.prefs.label.categories_sorting_order": "Categories sorting",
|
||||||
|
@ -403,6 +403,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "OPML file",
|
"form.import.label.file": "OPML file",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -391,7 +391,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Gesto para navegar entre entradas",
|
"form.prefs.label.gesture_nav": "Gesto para navegar entre entradas",
|
||||||
"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.custom_js": "JS personalizado",
|
"form.prefs.label.custom_js": "JavaScript personalizado",
|
||||||
"form.prefs.label.entry_order": "Columna de clasificación de artículos",
|
"form.prefs.label.entry_order": "Columna de clasificación de artículos",
|
||||||
"form.prefs.label.default_home_page": "Página de inicio por defecto",
|
"form.prefs.label.default_home_page": "Página de inicio por defecto",
|
||||||
"form.prefs.label.categories_sorting_order": "Clasificación por categorías",
|
"form.prefs.label.categories_sorting_order": "Clasificación por categorías",
|
||||||
|
@ -403,6 +403,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Ajustes de la autentificación",
|
"form.prefs.fieldset.authentication_settings": "Ajustes de la autentificación",
|
||||||
"form.prefs.fieldset.reader_settings": "Ajustes del lector",
|
"form.prefs.fieldset.reader_settings": "Ajustes del lector",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Ajustes globales del feed",
|
"form.prefs.fieldset.global_feed_settings": "Ajustes globales del feed",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "Archivo OPML",
|
"form.import.label.file": "Archivo OPML",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Guardar artículos en Betula",
|
"form.integration.betula_activate": "Guardar artículos en Betula",
|
||||||
|
|
|
@ -391,7 +391,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Ele siirtyäksesi merkintöjen välillä",
|
"form.prefs.label.gesture_nav": "Ele siirtyäksesi merkintöjen välillä",
|
||||||
"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.custom_js": "Mukautettu JS",
|
"form.prefs.label.custom_js": "Mukautettu JavaScript",
|
||||||
"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.prefs.label.default_home_page": "Oletusarvoinen etusivu",
|
||||||
"form.prefs.label.categories_sorting_order": "Kategorioiden lajittelu",
|
"form.prefs.label.categories_sorting_order": "Kategorioiden lajittelu",
|
||||||
|
@ -403,6 +403,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "OPML-tiedosto",
|
"form.import.label.file": "OPML-tiedosto",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -391,7 +391,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Geste pour naviguer entre les entrées",
|
"form.prefs.label.gesture_nav": "Geste pour naviguer entre les entrées",
|
||||||
"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": "Feuille de style personnalisée",
|
"form.prefs.label.custom_css": "Feuille de style personnalisée",
|
||||||
"form.prefs.label.custom_js": "Script personnalisée",
|
"form.prefs.label.custom_js": "Code JavaScript 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.prefs.label.default_home_page": "Page d'accueil par défaut",
|
||||||
"form.prefs.label.categories_sorting_order": "Colonne de tri des catégories",
|
"form.prefs.label.categories_sorting_order": "Colonne de tri des catégories",
|
||||||
|
@ -403,6 +403,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Paramètres d'authentification",
|
"form.prefs.fieldset.authentication_settings": "Paramètres d'authentification",
|
||||||
"form.prefs.fieldset.reader_settings": "Paramètres du lecteur",
|
"form.prefs.fieldset.reader_settings": "Paramètres du lecteur",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Paramètres globaux des abonnements",
|
"form.prefs.fieldset.global_feed_settings": "Paramètres globaux des abonnements",
|
||||||
|
"form.prefs.label.external_font_hosts": "Polices externes autorisées",
|
||||||
|
"form.prefs.help.external_font_hosts": "Liste de domaine externes autorisés, séparés par des espaces. Par exemple : « fonts.gstatic.com fonts.googleapis.com ».",
|
||||||
|
"error.settings_invalid_domain_list": "Liste de domaines invalide. Veuillez fournir une liste de domaines séparés par des espaces.",
|
||||||
"form.import.label.file": "Fichier OPML",
|
"form.import.label.file": "Fichier OPML",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Sauvegarder les entrées vers Betula",
|
"form.integration.betula_activate": "Sauvegarder les entrées vers Betula",
|
||||||
|
|
|
@ -403,6 +403,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "ओपीएमएल फ़ाइल",
|
"form.import.label.file": "ओपीएमएल फ़ाइल",
|
||||||
"form.import.label.url": "यूआरएल",
|
"form.import.label.url": "यूआरएल",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -381,7 +381,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Isyarat untuk menavigasi antar entri",
|
"form.prefs.label.gesture_nav": "Isyarat untuk menavigasi antar entri",
|
||||||
"form.prefs.label.show_reading_time": "Tampilkan perkiraan waktu baca untuk artikel",
|
"form.prefs.label.show_reading_time": "Tampilkan perkiraan waktu baca untuk artikel",
|
||||||
"form.prefs.label.custom_css": "Modifikasi CSS",
|
"form.prefs.label.custom_css": "Modifikasi CSS",
|
||||||
"form.prefs.label.custom_js": "Modifikasi JS",
|
"form.prefs.label.custom_js": "Modifikasi JavaScript",
|
||||||
"form.prefs.label.entry_order": "Pengurutan Kolom Entri",
|
"form.prefs.label.entry_order": "Pengurutan Kolom Entri",
|
||||||
"form.prefs.label.default_home_page": "Beranda Baku",
|
"form.prefs.label.default_home_page": "Beranda Baku",
|
||||||
"form.prefs.label.categories_sorting_order": "Pengurutan Kategori",
|
"form.prefs.label.categories_sorting_order": "Pengurutan Kategori",
|
||||||
|
@ -393,6 +393,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "Berkas OPML",
|
"form.import.label.file": "Berkas OPML",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -391,7 +391,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Gesto per navigare tra le voci",
|
"form.prefs.label.gesture_nav": "Gesto per navigare tra le voci",
|
||||||
"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.custom_js": "JS personalizzati",
|
"form.prefs.label.custom_js": "JavaScript 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.prefs.label.default_home_page": "Pagina iniziale predefinita",
|
||||||
"form.prefs.label.categories_sorting_order": "Ordinamento delle categorie",
|
"form.prefs.label.categories_sorting_order": "Ordinamento delle categorie",
|
||||||
|
@ -403,6 +403,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "File OPML",
|
"form.import.label.file": "File OPML",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -381,7 +381,7 @@
|
||||||
"form.prefs.label.gesture_nav": "エントリ間を移動するジェスチャー",
|
"form.prefs.label.gesture_nav": "エントリ間を移動するジェスチャー",
|
||||||
"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.custom_js": "カスタム JS",
|
"form.prefs.label.custom_js": "カスタム JavaScript",
|
||||||
"form.prefs.label.entry_order": "記事の表示順の基準",
|
"form.prefs.label.entry_order": "記事の表示順の基準",
|
||||||
"form.prefs.label.default_home_page": "デフォルトのトップページ",
|
"form.prefs.label.default_home_page": "デフォルトのトップページ",
|
||||||
"form.prefs.label.categories_sorting_order": "カテゴリの表示順",
|
"form.prefs.label.categories_sorting_order": "カテゴリの表示順",
|
||||||
|
@ -393,6 +393,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "OPML ファイル",
|
"form.import.label.file": "OPML ファイル",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -391,7 +391,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Gebaar om tussen artikelen te navigeren",
|
"form.prefs.label.gesture_nav": "Gebaar om tussen artikelen te navigeren",
|
||||||
"form.prefs.label.show_reading_time": "Toon geschatte leestijd van artikelen",
|
"form.prefs.label.show_reading_time": "Toon geschatte leestijd van artikelen",
|
||||||
"form.prefs.label.custom_css": "Aangepaste CSS",
|
"form.prefs.label.custom_css": "Aangepaste CSS",
|
||||||
"form.prefs.label.custom_js": "Aangepaste JS",
|
"form.prefs.label.custom_js": "Aangepaste JavaScript",
|
||||||
"form.prefs.label.entry_order": "Artikelen sorteren",
|
"form.prefs.label.entry_order": "Artikelen sorteren",
|
||||||
"form.prefs.label.default_home_page": "Startpagina",
|
"form.prefs.label.default_home_page": "Startpagina",
|
||||||
"form.prefs.label.categories_sorting_order": "Volgorde categorieën",
|
"form.prefs.label.categories_sorting_order": "Volgorde categorieën",
|
||||||
|
@ -403,6 +403,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authenticatie Instellingen",
|
"form.prefs.fieldset.authentication_settings": "Authenticatie Instellingen",
|
||||||
"form.prefs.fieldset.reader_settings": "Lees Instellingen",
|
"form.prefs.fieldset.reader_settings": "Lees Instellingen",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Globale Feed Instellingen",
|
"form.prefs.fieldset.global_feed_settings": "Globale Feed Instellingen",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "OPML-bestand",
|
"form.import.label.file": "OPML-bestand",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Artikelen opslaan in Betula",
|
"form.integration.betula_activate": "Artikelen opslaan in Betula",
|
||||||
|
|
|
@ -401,7 +401,7 @@
|
||||||
"form.prefs.select.tap": "Podwójne wciśnięcie",
|
"form.prefs.select.tap": "Podwójne wciśnięcie",
|
||||||
"form.prefs.select.swipe": "Trzepnąć",
|
"form.prefs.select.swipe": "Trzepnąć",
|
||||||
"form.prefs.label.custom_css": "Niestandardowy CSS",
|
"form.prefs.label.custom_css": "Niestandardowy CSS",
|
||||||
"form.prefs.label.custom_js": "Niestandardowy JS",
|
"form.prefs.label.custom_js": "Niestandardowy JavaScript",
|
||||||
"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.prefs.label.default_home_page": "Domyślna strona główna",
|
||||||
"form.prefs.label.categories_sorting_order": "Sortowanie kategorii",
|
"form.prefs.label.categories_sorting_order": "Sortowanie kategorii",
|
||||||
|
@ -413,6 +413,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "Plik OPML",
|
"form.import.label.file": "Plik OPML",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -391,7 +391,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Gesto para navegar entre as entradas",
|
"form.prefs.label.gesture_nav": "Gesto para navegar entre as entradas",
|
||||||
"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.custom_js": "JS customizado",
|
"form.prefs.label.custom_js": "JavaScript 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.prefs.label.default_home_page": "Página inicial predefinida",
|
||||||
"form.prefs.label.categories_sorting_order": "Classificação das categorias",
|
"form.prefs.label.categories_sorting_order": "Classificação das categorias",
|
||||||
|
@ -403,6 +403,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "Arquivo OPML",
|
"form.import.label.file": "Arquivo OPML",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -401,7 +401,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Жест для перехода между статьями",
|
"form.prefs.label.gesture_nav": "Жест для перехода между статьями",
|
||||||
"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.custom_js": "Пользовательский JS",
|
"form.prefs.label.custom_js": "Пользовательский JavaScript",
|
||||||
"form.prefs.label.entry_order": "Столбец сортировки статей",
|
"form.prefs.label.entry_order": "Столбец сортировки статей",
|
||||||
"form.prefs.label.default_home_page": "Домашняя страница по умолчанию",
|
"form.prefs.label.default_home_page": "Домашняя страница по умолчанию",
|
||||||
"form.prefs.label.categories_sorting_order": "Сортировка категорий",
|
"form.prefs.label.categories_sorting_order": "Сортировка категорий",
|
||||||
|
@ -413,6 +413,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "OPML файл",
|
"form.import.label.file": "OPML файл",
|
||||||
"form.import.label.url": "Ссылка",
|
"form.import.label.url": "Ссылка",
|
||||||
"form.integration.betula_activate": "Сохранять статьи в Бетулу",
|
"form.integration.betula_activate": "Сохранять статьи в Бетулу",
|
||||||
|
|
|
@ -293,7 +293,7 @@
|
||||||
"form.prefs.label.categories_sorting_order": "Kategori sıralaması",
|
"form.prefs.label.categories_sorting_order": "Kategori sıralaması",
|
||||||
"form.prefs.label.cjk_reading_speed": "Çince, Korece ve Japonca için okuma hızı (dakika başına karakter)",
|
"form.prefs.label.cjk_reading_speed": "Çince, Korece ve Japonca için okuma hızı (dakika başına karakter)",
|
||||||
"form.prefs.label.custom_css": "Özel CSS",
|
"form.prefs.label.custom_css": "Özel CSS",
|
||||||
"form.prefs.label.custom_js": "Özel JS",
|
"form.prefs.label.custom_js": "Özel JavaScript",
|
||||||
"form.prefs.label.default_home_page": "Varsayılan ana sayfa",
|
"form.prefs.label.default_home_page": "Varsayılan ana sayfa",
|
||||||
"form.prefs.label.default_reading_speed": "Diğer diller için okuma hızı (dakika başına kelime)",
|
"form.prefs.label.default_reading_speed": "Diğer diller için okuma hızı (dakika başına kelime)",
|
||||||
"form.prefs.label.display_mode": "Progressive Web App (PWA) görüntüleme modu",
|
"form.prefs.label.display_mode": "Progressive Web App (PWA) görüntüleme modu",
|
||||||
|
@ -325,6 +325,9 @@
|
||||||
"form.prefs.select.swipe": "Kaydırma",
|
"form.prefs.select.swipe": "Kaydırma",
|
||||||
"form.prefs.select.tap": "Çift dokunma",
|
"form.prefs.select.tap": "Çift dokunma",
|
||||||
"form.prefs.select.unread_count": "Okunmamış sayısı",
|
"form.prefs.select.unread_count": "Okunmamış sayısı",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.submit.loading": "Yükleniyor...",
|
"form.submit.loading": "Yükleniyor...",
|
||||||
"form.submit.saving": "Kaydediliyor...",
|
"form.submit.saving": "Kaydediliyor...",
|
||||||
"form.user.label.admin": "Yönetici",
|
"form.user.label.admin": "Yönetici",
|
||||||
|
|
|
@ -401,7 +401,7 @@
|
||||||
"form.prefs.label.gesture_nav": "Жест для переходу між записами",
|
"form.prefs.label.gesture_nav": "Жест для переходу між записами",
|
||||||
"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.custom_js": "Спеціальний JS",
|
"form.prefs.label.custom_js": "Спеціальний JavaScript",
|
||||||
"form.prefs.label.entry_order": "Стовпець сортування записів",
|
"form.prefs.label.entry_order": "Стовпець сортування записів",
|
||||||
"form.prefs.label.default_home_page": "Домашня сторінка за умовчанням",
|
"form.prefs.label.default_home_page": "Домашня сторінка за умовчанням",
|
||||||
"form.prefs.label.categories_sorting_order": "Сортування за категоріями",
|
"form.prefs.label.categories_sorting_order": "Сортування за категоріями",
|
||||||
|
@ -413,6 +413,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
"form.prefs.fieldset.authentication_settings": "Authentication Settings",
|
||||||
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
"form.prefs.fieldset.reader_settings": "Reader Settings",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "Файл OPML",
|
"form.import.label.file": "Файл OPML",
|
||||||
"form.import.label.url": "URL-адреса",
|
"form.import.label.url": "URL-адреса",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -381,7 +381,7 @@
|
||||||
"form.prefs.label.gesture_nav": "在条目之间导航的手势",
|
"form.prefs.label.gesture_nav": "在条目之间导航的手势",
|
||||||
"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.custom_js": "自定义 JS",
|
"form.prefs.label.custom_js": "自定义 JavaScript",
|
||||||
"form.prefs.label.entry_order": "文章排序依据",
|
"form.prefs.label.entry_order": "文章排序依据",
|
||||||
"form.prefs.label.default_home_page": "默认主页",
|
"form.prefs.label.default_home_page": "默认主页",
|
||||||
"form.prefs.label.categories_sorting_order": "分类排序",
|
"form.prefs.label.categories_sorting_order": "分类排序",
|
||||||
|
@ -393,6 +393,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "用户认证设置",
|
"form.prefs.fieldset.authentication_settings": "用户认证设置",
|
||||||
"form.prefs.fieldset.reader_settings": "阅读器设置",
|
"form.prefs.fieldset.reader_settings": "阅读器设置",
|
||||||
"form.prefs.fieldset.global_feed_settings": "全局订阅源设置",
|
"form.prefs.fieldset.global_feed_settings": "全局订阅源设置",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "OPML 文件",
|
"form.import.label.file": "OPML 文件",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "保存文章到 Betula",
|
"form.integration.betula_activate": "保存文章到 Betula",
|
||||||
|
|
|
@ -381,7 +381,7 @@
|
||||||
"form.prefs.label.gesture_nav": "在條目之間導航的手勢",
|
"form.prefs.label.gesture_nav": "在條目之間導航的手勢",
|
||||||
"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.custom_js": "自定義 JS",
|
"form.prefs.label.custom_js": "自定義 JavaScript",
|
||||||
"form.prefs.label.entry_order": "文章排序依據",
|
"form.prefs.label.entry_order": "文章排序依據",
|
||||||
"form.prefs.label.default_home_page": "預設主頁",
|
"form.prefs.label.default_home_page": "預設主頁",
|
||||||
"form.prefs.label.categories_sorting_order": "分類排序",
|
"form.prefs.label.categories_sorting_order": "分類排序",
|
||||||
|
@ -393,6 +393,9 @@
|
||||||
"form.prefs.fieldset.authentication_settings": "使用者認證設定",
|
"form.prefs.fieldset.authentication_settings": "使用者認證設定",
|
||||||
"form.prefs.fieldset.reader_settings": "閱讀器設定",
|
"form.prefs.fieldset.reader_settings": "閱讀器設定",
|
||||||
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
"form.prefs.fieldset.global_feed_settings": "Global Feed Settings",
|
||||||
|
"form.prefs.label.external_font_hosts": "External font hosts",
|
||||||
|
"form.prefs.help.external_font_hosts": "Space separated list of external font hosts to allow. For example: \"fonts.gstatic.com fonts.googleapis.com\".",
|
||||||
|
"error.settings_invalid_domain_list": "Invalid domain list. Please provide a space separated list of domains.",
|
||||||
"form.import.label.file": "OPML 檔案",
|
"form.import.label.file": "OPML 檔案",
|
||||||
"form.import.label.url": "URL",
|
"form.import.label.url": "URL",
|
||||||
"form.integration.betula_activate": "Save entries to Betula",
|
"form.integration.betula_activate": "Save entries to Betula",
|
||||||
|
|
|
@ -22,6 +22,7 @@ type User struct {
|
||||||
EntryOrder string `json:"entry_sorting_order"`
|
EntryOrder string `json:"entry_sorting_order"`
|
||||||
Stylesheet string `json:"stylesheet"`
|
Stylesheet string `json:"stylesheet"`
|
||||||
CustomJS string `json:"custom_js"`
|
CustomJS string `json:"custom_js"`
|
||||||
|
ExternalFontHosts string `json:"external_font_hosts"`
|
||||||
GoogleID string `json:"google_id"`
|
GoogleID string `json:"google_id"`
|
||||||
OpenIDConnectID string `json:"openid_connect_id"`
|
OpenIDConnectID string `json:"openid_connect_id"`
|
||||||
EntriesPerPage int `json:"entries_per_page"`
|
EntriesPerPage int `json:"entries_per_page"`
|
||||||
|
@ -62,6 +63,7 @@ type UserModificationRequest struct {
|
||||||
EntryOrder *string `json:"entry_sorting_order"`
|
EntryOrder *string `json:"entry_sorting_order"`
|
||||||
Stylesheet *string `json:"stylesheet"`
|
Stylesheet *string `json:"stylesheet"`
|
||||||
CustomJS *string `json:"custom_js"`
|
CustomJS *string `json:"custom_js"`
|
||||||
|
ExternalFontHosts *string `json:"external_font_hosts"`
|
||||||
GoogleID *string `json:"google_id"`
|
GoogleID *string `json:"google_id"`
|
||||||
OpenIDConnectID *string `json:"openid_connect_id"`
|
OpenIDConnectID *string `json:"openid_connect_id"`
|
||||||
EntriesPerPage *int `json:"entries_per_page"`
|
EntriesPerPage *int `json:"entries_per_page"`
|
||||||
|
@ -124,6 +126,10 @@ func (u *UserModificationRequest) Patch(user *User) {
|
||||||
user.CustomJS = *u.CustomJS
|
user.CustomJS = *u.CustomJS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if u.ExternalFontHosts != nil {
|
||||||
|
user.ExternalFontHosts = *u.ExternalFontHosts
|
||||||
|
}
|
||||||
|
|
||||||
if u.GoogleID != nil {
|
if u.GoogleID != nil {
|
||||||
user.GoogleID = *u.GoogleID
|
user.GoogleID = *u.GoogleID
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,7 @@ func (s *Storage) CreateUser(userCreationRequest *model.UserCreationRequest) (*m
|
||||||
gesture_nav,
|
gesture_nav,
|
||||||
stylesheet,
|
stylesheet,
|
||||||
custom_js,
|
custom_js,
|
||||||
|
external_font_hosts,
|
||||||
google_id,
|
google_id,
|
||||||
openid_connect_id,
|
openid_connect_id,
|
||||||
display_mode,
|
display_mode,
|
||||||
|
@ -126,6 +127,7 @@ func (s *Storage) CreateUser(userCreationRequest *model.UserCreationRequest) (*m
|
||||||
&user.GestureNav,
|
&user.GestureNav,
|
||||||
&user.Stylesheet,
|
&user.Stylesheet,
|
||||||
&user.CustomJS,
|
&user.CustomJS,
|
||||||
|
&user.ExternalFontHosts,
|
||||||
&user.GoogleID,
|
&user.GoogleID,
|
||||||
&user.OpenIDConnectID,
|
&user.OpenIDConnectID,
|
||||||
&user.DisplayMode,
|
&user.DisplayMode,
|
||||||
|
@ -165,6 +167,8 @@ func (s *Storage) CreateUser(userCreationRequest *model.UserCreationRequest) (*m
|
||||||
|
|
||||||
// UpdateUser updates a user.
|
// UpdateUser updates a user.
|
||||||
func (s *Storage) UpdateUser(user *model.User) error {
|
func (s *Storage) UpdateUser(user *model.User) error {
|
||||||
|
user.ExternalFontHosts = strings.TrimSpace(user.ExternalFontHosts)
|
||||||
|
|
||||||
if user.Password != "" {
|
if user.Password != "" {
|
||||||
hashedPassword, err := crypto.HashPassword(user.Password)
|
hashedPassword, err := crypto.HashPassword(user.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -187,21 +191,22 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
||||||
gesture_nav=$12,
|
gesture_nav=$12,
|
||||||
stylesheet=$13,
|
stylesheet=$13,
|
||||||
custom_js=$14,
|
custom_js=$14,
|
||||||
google_id=$15,
|
external_font_hosts=$15,
|
||||||
openid_connect_id=$16,
|
google_id=$16,
|
||||||
display_mode=$17,
|
openid_connect_id=$167,
|
||||||
entry_order=$18,
|
display_mode=$18,
|
||||||
default_reading_speed=$19,
|
entry_order=$19,
|
||||||
cjk_reading_speed=$20,
|
default_reading_speed=$20,
|
||||||
default_home_page=$21,
|
cjk_reading_speed=$21,
|
||||||
categories_sorting_order=$22,
|
default_home_page=$22,
|
||||||
mark_read_on_view=$23,
|
categories_sorting_order=$23,
|
||||||
mark_read_on_media_player_completion=$24,
|
mark_read_on_view=$24,
|
||||||
media_playback_rate=$25,
|
mark_read_on_media_player_completion=$25,
|
||||||
block_filter_entry_rules=$26,
|
media_playback_rate=$26,
|
||||||
keep_filter_entry_rules=$27
|
block_filter_entry_rules=$27,
|
||||||
|
keep_filter_entry_rules=$28
|
||||||
WHERE
|
WHERE
|
||||||
id=$28
|
id=$29
|
||||||
`
|
`
|
||||||
|
|
||||||
_, err = s.db.Exec(
|
_, err = s.db.Exec(
|
||||||
|
@ -220,6 +225,7 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
||||||
user.GestureNav,
|
user.GestureNav,
|
||||||
user.Stylesheet,
|
user.Stylesheet,
|
||||||
user.CustomJS,
|
user.CustomJS,
|
||||||
|
user.ExternalFontHosts,
|
||||||
user.GoogleID,
|
user.GoogleID,
|
||||||
user.OpenIDConnectID,
|
user.OpenIDConnectID,
|
||||||
user.DisplayMode,
|
user.DisplayMode,
|
||||||
|
@ -254,21 +260,22 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
||||||
gesture_nav=$11,
|
gesture_nav=$11,
|
||||||
stylesheet=$12,
|
stylesheet=$12,
|
||||||
custom_js=$13,
|
custom_js=$13,
|
||||||
google_id=$14,
|
external_font_hosts=$14,
|
||||||
openid_connect_id=$15,
|
google_id=$15,
|
||||||
display_mode=$16,
|
openid_connect_id=$16,
|
||||||
entry_order=$17,
|
display_mode=$17,
|
||||||
default_reading_speed=$18,
|
entry_order=$18,
|
||||||
cjk_reading_speed=$19,
|
default_reading_speed=$19,
|
||||||
default_home_page=$20,
|
cjk_reading_speed=$20,
|
||||||
categories_sorting_order=$21,
|
default_home_page=$21,
|
||||||
mark_read_on_view=$22,
|
categories_sorting_order=$22,
|
||||||
mark_read_on_media_player_completion=$23,
|
mark_read_on_view=$23,
|
||||||
media_playback_rate=$24,
|
mark_read_on_media_player_completion=$24,
|
||||||
block_filter_entry_rules=$25,
|
media_playback_rate=$25,
|
||||||
keep_filter_entry_rules=$26
|
block_filter_entry_rules=$26,
|
||||||
|
keep_filter_entry_rules=$27
|
||||||
WHERE
|
WHERE
|
||||||
id=$27
|
id=$28
|
||||||
`
|
`
|
||||||
|
|
||||||
_, err := s.db.Exec(
|
_, err := s.db.Exec(
|
||||||
|
@ -286,6 +293,7 @@ func (s *Storage) UpdateUser(user *model.User) error {
|
||||||
user.GestureNav,
|
user.GestureNav,
|
||||||
user.Stylesheet,
|
user.Stylesheet,
|
||||||
user.CustomJS,
|
user.CustomJS,
|
||||||
|
user.ExternalFontHosts,
|
||||||
user.GoogleID,
|
user.GoogleID,
|
||||||
user.OpenIDConnectID,
|
user.OpenIDConnectID,
|
||||||
user.DisplayMode,
|
user.DisplayMode,
|
||||||
|
@ -339,6 +347,7 @@ func (s *Storage) UserByID(userID int64) (*model.User, error) {
|
||||||
last_login_at,
|
last_login_at,
|
||||||
stylesheet,
|
stylesheet,
|
||||||
custom_js,
|
custom_js,
|
||||||
|
external_font_hosts,
|
||||||
google_id,
|
google_id,
|
||||||
openid_connect_id,
|
openid_connect_id,
|
||||||
display_mode,
|
display_mode,
|
||||||
|
@ -379,6 +388,7 @@ func (s *Storage) UserByUsername(username string) (*model.User, error) {
|
||||||
last_login_at,
|
last_login_at,
|
||||||
stylesheet,
|
stylesheet,
|
||||||
custom_js,
|
custom_js,
|
||||||
|
external_font_hosts,
|
||||||
google_id,
|
google_id,
|
||||||
openid_connect_id,
|
openid_connect_id,
|
||||||
display_mode,
|
display_mode,
|
||||||
|
@ -419,6 +429,7 @@ func (s *Storage) UserByField(field, value string) (*model.User, error) {
|
||||||
last_login_at,
|
last_login_at,
|
||||||
stylesheet,
|
stylesheet,
|
||||||
custom_js,
|
custom_js,
|
||||||
|
external_font_hosts,
|
||||||
google_id,
|
google_id,
|
||||||
openid_connect_id,
|
openid_connect_id,
|
||||||
display_mode,
|
display_mode,
|
||||||
|
@ -466,6 +477,7 @@ func (s *Storage) UserByAPIKey(token string) (*model.User, error) {
|
||||||
u.last_login_at,
|
u.last_login_at,
|
||||||
u.stylesheet,
|
u.stylesheet,
|
||||||
u.custom_js,
|
u.custom_js,
|
||||||
|
u.external_font_hosts,
|
||||||
u.google_id,
|
u.google_id,
|
||||||
u.openid_connect_id,
|
u.openid_connect_id,
|
||||||
u.display_mode,
|
u.display_mode,
|
||||||
|
@ -507,6 +519,7 @@ func (s *Storage) fetchUser(query string, args ...interface{}) (*model.User, err
|
||||||
&user.LastLoginAt,
|
&user.LastLoginAt,
|
||||||
&user.Stylesheet,
|
&user.Stylesheet,
|
||||||
&user.CustomJS,
|
&user.CustomJS,
|
||||||
|
&user.ExternalFontHosts,
|
||||||
&user.GoogleID,
|
&user.GoogleID,
|
||||||
&user.OpenIDConnectID,
|
&user.OpenIDConnectID,
|
||||||
&user.DisplayMode,
|
&user.DisplayMode,
|
||||||
|
@ -620,6 +633,7 @@ func (s *Storage) Users() (model.Users, error) {
|
||||||
last_login_at,
|
last_login_at,
|
||||||
stylesheet,
|
stylesheet,
|
||||||
custom_js,
|
custom_js,
|
||||||
|
external_font_hosts,
|
||||||
google_id,
|
google_id,
|
||||||
openid_connect_id,
|
openid_connect_id,
|
||||||
display_mode,
|
display_mode,
|
||||||
|
@ -662,6 +676,7 @@ func (s *Storage) Users() (model.Users, error) {
|
||||||
&user.LastLoginAt,
|
&user.LastLoginAt,
|
||||||
&user.Stylesheet,
|
&user.Stylesheet,
|
||||||
&user.CustomJS,
|
&user.CustomJS,
|
||||||
|
&user.ExternalFontHosts,
|
||||||
&user.GoogleID,
|
&user.GoogleID,
|
||||||
&user.OpenIDConnectID,
|
&user.OpenIDConnectID,
|
||||||
&user.DisplayMode,
|
&user.DisplayMode,
|
||||||
|
|
|
@ -36,10 +36,12 @@
|
||||||
|
|
||||||
{{ if .user }}
|
{{ if .user }}
|
||||||
{{ $cspNonce := nonce }}
|
{{ $cspNonce := nonce }}
|
||||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data:; media-src *; frame-src *; style-src 'self'{{ if .user.Stylesheet }} 'nonce-{{ $cspNonce }}'{{ end }}{{ if .user.CustomJS }}; script-src 'self' 'nonce-{{ $cspNonce }}'{{ end }}; require-trusted-types-for 'script'; trusted-types ttpolicy;">
|
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data:; media-src *; frame-src *; {{ if .user.ExternalFontHosts }}font-src {{ .user.ExternalFontHosts }}; {{ end }}style-src 'self'{{ if .user.Stylesheet }}{{ if .user.ExternalFontHosts }} {{ .user.ExternalFontHosts }}{{ end }} 'nonce-{{ $cspNonce }}'{{ end }}{{ if .user.CustomJS }}; script-src 'self' 'nonce-{{ $cspNonce }}'{{ end }}; require-trusted-types-for 'script'; trusted-types ttpolicy;">
|
||||||
|
|
||||||
{{ if .user.Stylesheet }}
|
{{ if .user.Stylesheet }}
|
||||||
<style nonce="{{ $cspNonce }}">{{ .user.Stylesheet | safeCSS }}</style>
|
<style nonce="{{ $cspNonce }}">{{ .user.Stylesheet | safeCSS }}</style>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
{{ if .user.CustomJS }}
|
{{ if .user.CustomJS }}
|
||||||
<script type="module" nonce="{{ $cspNonce }}">{{ .user.CustomJS | safeJS }}</script>
|
<script type="module" nonce="{{ $cspNonce }}">{{ .user.CustomJS | safeJS }}</script>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
|
@ -210,6 +210,10 @@
|
||||||
<label for="form-custom-css">{{t "form.prefs.label.custom_css" }}</label>
|
<label for="form-custom-css">{{t "form.prefs.label.custom_css" }}</label>
|
||||||
<textarea id="form-custom-css" name="custom_css" cols="40" rows="10" spellcheck="false">{{ .form.CustomCSS }}</textarea>
|
<textarea id="form-custom-css" name="custom_css" cols="40" rows="10" spellcheck="false">{{ .form.CustomCSS }}</textarea>
|
||||||
|
|
||||||
|
<label for="form-external-font-hosts">{{t "form.prefs.label.external_font_hosts" }}</label>
|
||||||
|
<input type="text" id="form-external-font-hosts" name="external_font_hosts" spellcheck="false" value="{{ .form.ExternalFontHosts }}">
|
||||||
|
<div class="form-help">{{t "form.prefs.help.external_font_hosts" }}</div>
|
||||||
|
|
||||||
<label for="form-custom-js">{{t "form.prefs.label.custom_js" }}</label>
|
<label for="form-custom-js">{{t "form.prefs.label.custom_js" }}</label>
|
||||||
<textarea id="form-custom-js" name="custom_js" cols="40" rows="10" spellcheck="false">{{ .form.CustomJS }}</textarea>
|
<textarea id="form-custom-js" name="custom_js" cols="40" rows="10" spellcheck="false">{{ .form.CustomJS }}</textarea>
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"miniflux.app/v2/internal/config"
|
"miniflux.app/v2/internal/config"
|
||||||
"miniflux.app/v2/internal/locale"
|
"miniflux.app/v2/internal/locale"
|
||||||
"miniflux.app/v2/internal/model"
|
"miniflux.app/v2/internal/model"
|
||||||
|
"miniflux.app/v2/internal/validator"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MarkReadBehavior list all possible behaviors for automatically marking an entry as read
|
// MarkReadBehavior list all possible behaviors for automatically marking an entry as read
|
||||||
|
@ -37,6 +38,7 @@ type SettingsForm struct {
|
||||||
ShowReadingTime bool
|
ShowReadingTime bool
|
||||||
CustomCSS string
|
CustomCSS string
|
||||||
CustomJS string
|
CustomJS string
|
||||||
|
ExternalFontHosts string
|
||||||
EntrySwipe bool
|
EntrySwipe bool
|
||||||
GestureNav string
|
GestureNav string
|
||||||
DisplayMode string
|
DisplayMode string
|
||||||
|
@ -101,6 +103,7 @@ func (s *SettingsForm) Merge(user *model.User) *model.User {
|
||||||
user.ShowReadingTime = s.ShowReadingTime
|
user.ShowReadingTime = s.ShowReadingTime
|
||||||
user.Stylesheet = s.CustomCSS
|
user.Stylesheet = s.CustomCSS
|
||||||
user.CustomJS = s.CustomJS
|
user.CustomJS = s.CustomJS
|
||||||
|
user.ExternalFontHosts = s.ExternalFontHosts
|
||||||
user.EntrySwipe = s.EntrySwipe
|
user.EntrySwipe = s.EntrySwipe
|
||||||
user.GestureNav = s.GestureNav
|
user.GestureNav = s.GestureNav
|
||||||
user.DisplayMode = s.DisplayMode
|
user.DisplayMode = s.DisplayMode
|
||||||
|
@ -148,6 +151,12 @@ func (s *SettingsForm) Validate() *locale.LocalizedError {
|
||||||
return locale.NewLocalizedError("error.settings_media_playback_rate_range")
|
return locale.NewLocalizedError("error.settings_media_playback_rate_range")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s.ExternalFontHosts != "" {
|
||||||
|
if !validator.IsValidDomainList(s.ExternalFontHosts) {
|
||||||
|
return locale.NewLocalizedError("error.settings_invalid_domain_list")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,6 +192,7 @@ func NewSettingsForm(r *http.Request) *SettingsForm {
|
||||||
ShowReadingTime: r.FormValue("show_reading_time") == "1",
|
ShowReadingTime: r.FormValue("show_reading_time") == "1",
|
||||||
CustomCSS: r.FormValue("custom_css"),
|
CustomCSS: r.FormValue("custom_css"),
|
||||||
CustomJS: r.FormValue("custom_js"),
|
CustomJS: r.FormValue("custom_js"),
|
||||||
|
ExternalFontHosts: r.FormValue("external_font_hosts"),
|
||||||
EntrySwipe: r.FormValue("entry_swipe") == "1",
|
EntrySwipe: r.FormValue("entry_swipe") == "1",
|
||||||
GestureNav: r.FormValue("gesture_nav"),
|
GestureNav: r.FormValue("gesture_nav"),
|
||||||
DisplayMode: r.FormValue("display_mode"),
|
DisplayMode: r.FormValue("display_mode"),
|
||||||
|
|
|
@ -34,6 +34,7 @@ func (h *handler) showSettingsPage(w http.ResponseWriter, r *http.Request) {
|
||||||
ShowReadingTime: user.ShowReadingTime,
|
ShowReadingTime: user.ShowReadingTime,
|
||||||
CustomCSS: user.Stylesheet,
|
CustomCSS: user.Stylesheet,
|
||||||
CustomJS: user.CustomJS,
|
CustomJS: user.CustomJS,
|
||||||
|
ExternalFontHosts: user.ExternalFontHosts,
|
||||||
EntrySwipe: user.EntrySwipe,
|
EntrySwipe: user.EntrySwipe,
|
||||||
GestureNav: user.GestureNav,
|
GestureNav: user.GestureNav,
|
||||||
DisplayMode: user.DisplayMode,
|
DisplayMode: user.DisplayMode,
|
||||||
|
|
|
@ -85,6 +85,7 @@ func (h *handler) updateSettings(w http.ResponseWriter, r *http.Request) {
|
||||||
MediaPlaybackRate: model.OptionalNumber(settingsForm.MediaPlaybackRate),
|
MediaPlaybackRate: model.OptionalNumber(settingsForm.MediaPlaybackRate),
|
||||||
BlockFilterEntryRules: model.OptionalString(settingsForm.BlockFilterEntryRules),
|
BlockFilterEntryRules: model.OptionalString(settingsForm.BlockFilterEntryRules),
|
||||||
KeepFilterEntryRules: model.OptionalString(settingsForm.KeepFilterEntryRules),
|
KeepFilterEntryRules: model.OptionalString(settingsForm.KeepFilterEntryRules),
|
||||||
|
ExternalFontHosts: model.OptionalString(settingsForm.ExternalFontHosts),
|
||||||
}
|
}
|
||||||
|
|
||||||
if validationErr := validator.ValidateUserModification(h.store, loggedUser.ID, userModificationRequest); validationErr != nil {
|
if validationErr := validator.ValidateUserModification(h.store, loggedUser.ID, userModificationRequest); validationErr != nil {
|
||||||
|
|
|
@ -427,7 +427,6 @@ input[type="number"] {
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
width: 250px;
|
width: 250px;
|
||||||
font-size: 99%;
|
font-size: 99%;
|
||||||
margin-bottom: 10px;
|
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
appearance: none;
|
appearance: none;
|
||||||
}
|
}
|
||||||
|
@ -448,7 +447,8 @@ input[type="number"]:focus {
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="checkbox"] {
|
input[type="checkbox"] {
|
||||||
margin-bottom: 15px;
|
margin-top: 10px;
|
||||||
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
|
|
|
@ -123,6 +123,12 @@ func ValidateUserModification(store *storage.Storage, userID int64, changes *mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if changes.ExternalFontHosts != nil {
|
||||||
|
if !IsValidDomainList(*changes.ExternalFontHosts) {
|
||||||
|
return locale.NewLocalizedError("error.settings_invalid_domain_list")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var domainRegex = regexp.MustCompile(`^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$`)
|
||||||
|
|
||||||
// ValidateRange makes sure the offset/limit values are valid.
|
// ValidateRange makes sure the offset/limit values are valid.
|
||||||
func ValidateRange(offset, limit int) error {
|
func ValidateRange(offset, limit int) error {
|
||||||
if offset < 0 {
|
if offset < 0 {
|
||||||
|
@ -43,3 +46,24 @@ func IsValidURL(absoluteURL string) bool {
|
||||||
_, err := url.ParseRequestURI(absoluteURL)
|
_, err := url.ParseRequestURI(absoluteURL)
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsValidDomain(domain string) bool {
|
||||||
|
domain = strings.ToLower(domain)
|
||||||
|
|
||||||
|
if len(domain) < 1 || len(domain) > 253 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return domainRegex.MatchString(domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsValidDomainList(value string) bool {
|
||||||
|
domains := strings.Split(strings.TrimSpace(value), " ")
|
||||||
|
for _, domain := range domains {
|
||||||
|
if !IsValidDomain(domain) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
@ -59,3 +59,21 @@ func TestIsValidRegex(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsValidDomain(t *testing.T) {
|
||||||
|
scenarios := map[string]bool{
|
||||||
|
"example.org": true,
|
||||||
|
"example": false,
|
||||||
|
"example.": false,
|
||||||
|
"example..": false,
|
||||||
|
"mail.example.com:443": false,
|
||||||
|
"*.example.com": false,
|
||||||
|
}
|
||||||
|
|
||||||
|
for domain, expected := range scenarios {
|
||||||
|
result := IsValidDomain(domain)
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf(`Unexpected result, got %v instead of %v`, result, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue