| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
- // SPDX-License-Identifier: Apache-2.0
- package form // import "miniflux.app/v2/internal/ui/form"
- import (
- "net/http"
- "strconv"
- "miniflux.app/v2/internal/config"
- "miniflux.app/v2/internal/locale"
- "miniflux.app/v2/internal/model"
- "miniflux.app/v2/internal/validator"
- )
- // markReadBehavior list all possible behaviors for automatically marking an entry as read
- type markReadBehavior string
- const (
- NoAutoMarkAsRead markReadBehavior = "no-auto"
- MarkAsReadOnView markReadBehavior = "on-view"
- MarkAsReadOnViewButWaitForPlayerCompletion markReadBehavior = "on-view-but-wait-for-player-completion"
- MarkAsReadOnlyOnPlayerCompletion markReadBehavior = "on-player-completion"
- )
- // SettingsForm represents the settings form.
- type SettingsForm struct {
- Username string
- Password string
- Confirmation string
- Theme string
- Language string
- Timezone string
- EntryDirection string
- EntryOrder string
- EntriesPerPage int
- KeyboardShortcuts bool
- ShowReadingTime bool
- CustomCSS string
- CustomJS string
- ExternalFontHosts string
- EntrySwipe bool
- GestureNav string
- DisplayMode string
- DefaultReadingSpeed int
- CJKReadingSpeed int
- DefaultHomePage string
- CategoriesSortingOrder string
- MarkReadOnView bool
- // MarkReadBehavior is a string representation of the MarkReadOnView and MarkReadOnMediaPlayerCompletion fields together
- MarkReadBehavior markReadBehavior
- MediaPlaybackRate float64
- BlockFilterEntryRules string
- KeepFilterEntryRules string
- AlwaysOpenExternalLinks bool
- OpenExternalLinksInNewTab bool
- }
- // MarkAsReadBehavior returns the MarkReadBehavior from the given MarkReadOnView and MarkReadOnMediaPlayerCompletion values.
- // Useful to convert the values from the User model to the form
- func MarkAsReadBehavior(markReadOnView, markReadOnMediaPlayerCompletion bool) markReadBehavior {
- switch {
- case markReadOnView && !markReadOnMediaPlayerCompletion:
- return MarkAsReadOnView
- case markReadOnView && markReadOnMediaPlayerCompletion:
- return MarkAsReadOnViewButWaitForPlayerCompletion
- case !markReadOnView && markReadOnMediaPlayerCompletion:
- return MarkAsReadOnlyOnPlayerCompletion
- case !markReadOnView && !markReadOnMediaPlayerCompletion:
- fallthrough // Explicit defaulting
- default:
- return NoAutoMarkAsRead
- }
- }
- // extractMarkAsReadBehavior returns the MarkReadOnView and MarkReadOnMediaPlayerCompletion values from the given MarkReadBehavior.
- // Useful to extract the values from the form to the User model
- func extractMarkAsReadBehavior(behavior markReadBehavior) (markReadOnView, markReadOnMediaPlayerCompletion bool) {
- switch behavior {
- case MarkAsReadOnView:
- return true, false
- case MarkAsReadOnViewButWaitForPlayerCompletion:
- return true, true
- case MarkAsReadOnlyOnPlayerCompletion:
- return false, true
- case NoAutoMarkAsRead:
- fallthrough // Explicit defaulting
- default:
- return false, false
- }
- }
- // Merge updates the fields of the given user.
- func (s *SettingsForm) Merge(user *model.User) *model.User {
- if !config.Opts.DisableLocalAuth() {
- user.Username = s.Username
- }
- user.Theme = s.Theme
- user.Language = s.Language
- user.Timezone = s.Timezone
- user.EntryDirection = s.EntryDirection
- user.EntryOrder = s.EntryOrder
- user.EntriesPerPage = s.EntriesPerPage
- user.KeyboardShortcuts = s.KeyboardShortcuts
- user.ShowReadingTime = s.ShowReadingTime
- user.Stylesheet = s.CustomCSS
- user.CustomJS = s.CustomJS
- user.ExternalFontHosts = s.ExternalFontHosts
- user.EntrySwipe = s.EntrySwipe
- user.GestureNav = s.GestureNav
- user.DisplayMode = s.DisplayMode
- user.CJKReadingSpeed = s.CJKReadingSpeed
- user.DefaultReadingSpeed = s.DefaultReadingSpeed
- user.DefaultHomePage = s.DefaultHomePage
- user.CategoriesSortingOrder = s.CategoriesSortingOrder
- user.MediaPlaybackRate = s.MediaPlaybackRate
- user.BlockFilterEntryRules = s.BlockFilterEntryRules
- user.KeepFilterEntryRules = s.KeepFilterEntryRules
- user.AlwaysOpenExternalLinks = s.AlwaysOpenExternalLinks
- user.OpenExternalLinksInNewTab = s.OpenExternalLinksInNewTab
- MarkReadOnView, MarkReadOnMediaPlayerCompletion := extractMarkAsReadBehavior(s.MarkReadBehavior)
- user.MarkReadOnView = MarkReadOnView
- user.MarkReadOnMediaPlayerCompletion = MarkReadOnMediaPlayerCompletion
- if s.Password != "" {
- user.Password = s.Password
- }
- return user
- }
- // Validate makes sure the form values are valid.
- func (s *SettingsForm) Validate() *locale.LocalizedError {
- if (s.Username == "" && !config.Opts.DisableLocalAuth()) || s.Theme == "" || s.Language == "" || s.Timezone == "" || s.EntryDirection == "" || s.DisplayMode == "" || s.DefaultHomePage == "" {
- return locale.NewLocalizedError("error.settings_mandatory_fields")
- }
- if s.CJKReadingSpeed <= 0 || s.DefaultReadingSpeed <= 0 {
- return locale.NewLocalizedError("error.settings_reading_speed_is_positive")
- }
- if s.Confirmation == "" {
- // Firefox insists on auto-completing the password field.
- // If the confirmation field is blank, the user probably
- // didn't intend to change their password.
- s.Password = ""
- } else if s.Password != "" {
- if s.Password != s.Confirmation {
- return locale.NewLocalizedError("error.different_passwords")
- }
- }
- if s.MediaPlaybackRate < 0.25 || s.MediaPlaybackRate > 4 {
- 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
- }
- // NewSettingsForm returns a new SettingsForm.
- func NewSettingsForm(r *http.Request) *SettingsForm {
- entriesPerPage, err := strconv.ParseInt(r.FormValue("entries_per_page"), 10, 0)
- if err != nil {
- entriesPerPage = 0
- }
- defaultReadingSpeed, err := strconv.ParseInt(r.FormValue("default_reading_speed"), 10, 0)
- if err != nil {
- defaultReadingSpeed = 0
- }
- cjkReadingSpeed, err := strconv.ParseInt(r.FormValue("cjk_reading_speed"), 10, 0)
- if err != nil {
- cjkReadingSpeed = 0
- }
- mediaPlaybackRate, err := strconv.ParseFloat(r.FormValue("media_playback_rate"), 64)
- if err != nil {
- mediaPlaybackRate = 1
- }
- return &SettingsForm{
- Username: r.FormValue("username"),
- Password: r.FormValue("password"),
- Confirmation: r.FormValue("confirmation"),
- Theme: r.FormValue("theme"),
- Language: r.FormValue("language"),
- Timezone: r.FormValue("timezone"),
- EntryDirection: r.FormValue("entry_direction"),
- EntryOrder: r.FormValue("entry_order"),
- EntriesPerPage: int(entriesPerPage),
- KeyboardShortcuts: r.FormValue("keyboard_shortcuts") == "1",
- ShowReadingTime: r.FormValue("show_reading_time") == "1",
- CustomCSS: r.FormValue("custom_css"),
- CustomJS: r.FormValue("custom_js"),
- ExternalFontHosts: r.FormValue("external_font_hosts"),
- EntrySwipe: r.FormValue("entry_swipe") == "1",
- GestureNav: r.FormValue("gesture_nav"),
- DisplayMode: r.FormValue("display_mode"),
- DefaultReadingSpeed: int(defaultReadingSpeed),
- CJKReadingSpeed: int(cjkReadingSpeed),
- DefaultHomePage: r.FormValue("default_home_page"),
- CategoriesSortingOrder: r.FormValue("categories_sorting_order"),
- MarkReadOnView: r.FormValue("mark_read_on_view") == "1",
- MarkReadBehavior: markReadBehavior(r.FormValue("mark_read_behavior")),
- MediaPlaybackRate: mediaPlaybackRate,
- BlockFilterEntryRules: r.FormValue("block_filter_entry_rules"),
- KeepFilterEntryRules: r.FormValue("keep_filter_entry_rules"),
- AlwaysOpenExternalLinks: r.FormValue("always_open_external_links") == "1",
- OpenExternalLinksInNewTab: r.FormValue("open_external_links_in_new_tab") == "1",
- }
- }
|