mirror of
https://github.com/miniflux/v2.git
synced 2025-08-01 17:38:37 +00:00
feat: add option to always open articles externally
This commit is contained in:
parent
52b184394f
commit
09fb05aaaf
36 changed files with 397 additions and 303 deletions
|
@ -48,6 +48,11 @@ func (h *handler) showStarredEntryPage(w http.ResponseWriter, r *http.Request) {
|
|||
entry.Status = model.EntryStatusRead
|
||||
}
|
||||
|
||||
if user.AlwaysOpenExternalLinks {
|
||||
html.Redirect(w, r, entry.URL)
|
||||
return
|
||||
}
|
||||
|
||||
entryPaginationBuilder := storage.NewEntryPaginationBuilder(h.store, user.ID, entry.ID, user.EntryOrder, user.EntryDirection)
|
||||
entryPaginationBuilder.WithStarred()
|
||||
prevEntry, nextEntry, err := entryPaginationBuilder.Entries()
|
||||
|
|
|
@ -51,6 +51,11 @@ func (h *handler) showCategoryEntryPage(w http.ResponseWriter, r *http.Request)
|
|||
entry.Status = model.EntryStatusRead
|
||||
}
|
||||
|
||||
if user.AlwaysOpenExternalLinks {
|
||||
html.Redirect(w, r, entry.URL)
|
||||
return
|
||||
}
|
||||
|
||||
entryPaginationBuilder := storage.NewEntryPaginationBuilder(h.store, user.ID, entry.ID, user.EntryOrder, user.EntryDirection)
|
||||
entryPaginationBuilder.WithCategoryID(categoryID)
|
||||
prevEntry, nextEntry, err := entryPaginationBuilder.Entries()
|
||||
|
|
|
@ -51,6 +51,11 @@ func (h *handler) showFeedEntryPage(w http.ResponseWriter, r *http.Request) {
|
|||
entry.Status = model.EntryStatusRead
|
||||
}
|
||||
|
||||
if user.AlwaysOpenExternalLinks {
|
||||
html.Redirect(w, r, entry.URL)
|
||||
return
|
||||
}
|
||||
|
||||
entryPaginationBuilder := storage.NewEntryPaginationBuilder(h.store, user.ID, entry.ID, user.EntryOrder, user.EntryDirection)
|
||||
entryPaginationBuilder.WithFeedID(feedID)
|
||||
prevEntry, nextEntry, err := entryPaginationBuilder.Entries()
|
||||
|
|
|
@ -38,6 +38,11 @@ func (h *handler) showReadEntryPage(w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if user.AlwaysOpenExternalLinks {
|
||||
html.Redirect(w, r, entry.URL)
|
||||
return
|
||||
}
|
||||
|
||||
entryPaginationBuilder := storage.NewEntryPaginationBuilder(h.store, user.ID, entry.ID, "changed_at", "desc")
|
||||
entryPaginationBuilder.WithStatus(model.EntryStatusRead)
|
||||
prevEntry, nextEntry, err := entryPaginationBuilder.Entries()
|
||||
|
|
|
@ -50,6 +50,11 @@ func (h *handler) showSearchEntryPage(w http.ResponseWriter, r *http.Request) {
|
|||
entry.Status = model.EntryStatusRead
|
||||
}
|
||||
|
||||
if user.AlwaysOpenExternalLinks {
|
||||
html.Redirect(w, r, entry.URL)
|
||||
return
|
||||
}
|
||||
|
||||
entryPaginationBuilder := storage.NewEntryPaginationBuilder(h.store, user.ID, entry.ID, user.EntryOrder, user.EntryDirection)
|
||||
entryPaginationBuilder.WithSearchQuery(searchQuery)
|
||||
prevEntry, nextEntry, err := entryPaginationBuilder.Entries()
|
||||
|
|
|
@ -79,6 +79,11 @@ func (h *handler) showUnreadEntryPage(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
if user.AlwaysOpenExternalLinks {
|
||||
html.Redirect(w, r, entry.URL)
|
||||
return
|
||||
}
|
||||
|
||||
sess := session.New(h.store, request.SessionID(r))
|
||||
view := view.New(h.tpl, r, sess)
|
||||
view.Set("entry", entry)
|
||||
|
|
|
@ -48,10 +48,11 @@ type SettingsForm struct {
|
|||
CategoriesSortingOrder string
|
||||
MarkReadOnView bool
|
||||
// MarkReadBehavior is a string representation of the MarkReadOnView and MarkReadOnMediaPlayerCompletion fields together
|
||||
MarkReadBehavior MarkReadBehavior
|
||||
MediaPlaybackRate float64
|
||||
BlockFilterEntryRules string
|
||||
KeepFilterEntryRules string
|
||||
MarkReadBehavior MarkReadBehavior
|
||||
MediaPlaybackRate float64
|
||||
BlockFilterEntryRules string
|
||||
KeepFilterEntryRules string
|
||||
AlwaysOpenExternalLinks bool
|
||||
}
|
||||
|
||||
// MarkAsReadBehavior returns the MarkReadBehavior from the given MarkReadOnView and MarkReadOnMediaPlayerCompletion values.
|
||||
|
@ -114,6 +115,7 @@ func (s *SettingsForm) Merge(user *model.User) *model.User {
|
|||
user.MediaPlaybackRate = s.MediaPlaybackRate
|
||||
user.BlockFilterEntryRules = s.BlockFilterEntryRules
|
||||
user.KeepFilterEntryRules = s.KeepFilterEntryRules
|
||||
user.AlwaysOpenExternalLinks = s.AlwaysOpenExternalLinks
|
||||
|
||||
MarkReadOnView, MarkReadOnMediaPlayerCompletion := ExtractMarkAsReadBehavior(s.MarkReadBehavior)
|
||||
user.MarkReadOnView = MarkReadOnView
|
||||
|
@ -179,31 +181,32 @@ func NewSettingsForm(r *http.Request) *SettingsForm {
|
|||
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"),
|
||||
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",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,20 +9,21 @@ import (
|
|||
|
||||
func TestValid(t *testing.T) {
|
||||
settings := &SettingsForm{
|
||||
Username: "user",
|
||||
Password: "hunter2",
|
||||
Confirmation: "hunter2",
|
||||
Theme: "default",
|
||||
Language: "en_US",
|
||||
Timezone: "UTC",
|
||||
EntryDirection: "asc",
|
||||
EntriesPerPage: 50,
|
||||
DisplayMode: "standalone",
|
||||
GestureNav: "tap",
|
||||
DefaultReadingSpeed: 35,
|
||||
CJKReadingSpeed: 25,
|
||||
DefaultHomePage: "unread",
|
||||
MediaPlaybackRate: 1.25,
|
||||
Username: "user",
|
||||
Password: "hunter2",
|
||||
Confirmation: "hunter2",
|
||||
Theme: "default",
|
||||
Language: "en_US",
|
||||
Timezone: "UTC",
|
||||
EntryDirection: "asc",
|
||||
EntriesPerPage: 50,
|
||||
DisplayMode: "standalone",
|
||||
GestureNav: "tap",
|
||||
DefaultReadingSpeed: 35,
|
||||
CJKReadingSpeed: 25,
|
||||
DefaultHomePage: "unread",
|
||||
MediaPlaybackRate: 1.25,
|
||||
AlwaysOpenExternalLinks: true,
|
||||
}
|
||||
|
||||
err := settings.Validate()
|
||||
|
@ -33,20 +34,21 @@ func TestValid(t *testing.T) {
|
|||
|
||||
func TestConfirmationEmpty(t *testing.T) {
|
||||
settings := &SettingsForm{
|
||||
Username: "user",
|
||||
Password: "hunter2",
|
||||
Confirmation: "",
|
||||
Theme: "default",
|
||||
Language: "en_US",
|
||||
Timezone: "UTC",
|
||||
EntryDirection: "asc",
|
||||
EntriesPerPage: 50,
|
||||
DisplayMode: "standalone",
|
||||
GestureNav: "tap",
|
||||
DefaultReadingSpeed: 35,
|
||||
CJKReadingSpeed: 25,
|
||||
DefaultHomePage: "unread",
|
||||
MediaPlaybackRate: 1.25,
|
||||
Username: "user",
|
||||
Password: "hunter2",
|
||||
Confirmation: "",
|
||||
Theme: "default",
|
||||
Language: "en_US",
|
||||
Timezone: "UTC",
|
||||
EntryDirection: "asc",
|
||||
EntriesPerPage: 50,
|
||||
DisplayMode: "standalone",
|
||||
GestureNav: "tap",
|
||||
DefaultReadingSpeed: 35,
|
||||
CJKReadingSpeed: 25,
|
||||
DefaultHomePage: "unread",
|
||||
MediaPlaybackRate: 1.25,
|
||||
AlwaysOpenExternalLinks: true,
|
||||
}
|
||||
|
||||
err := settings.Validate()
|
||||
|
@ -61,20 +63,21 @@ func TestConfirmationEmpty(t *testing.T) {
|
|||
|
||||
func TestConfirmationIncorrect(t *testing.T) {
|
||||
settings := &SettingsForm{
|
||||
Username: "user",
|
||||
Password: "hunter2",
|
||||
Confirmation: "unter2",
|
||||
Theme: "default",
|
||||
Language: "en_US",
|
||||
Timezone: "UTC",
|
||||
EntryDirection: "asc",
|
||||
EntriesPerPage: 50,
|
||||
DisplayMode: "standalone",
|
||||
GestureNav: "tap",
|
||||
DefaultReadingSpeed: 35,
|
||||
CJKReadingSpeed: 25,
|
||||
DefaultHomePage: "unread",
|
||||
MediaPlaybackRate: 1.25,
|
||||
Username: "user",
|
||||
Password: "hunter2",
|
||||
Confirmation: "unter2",
|
||||
Theme: "default",
|
||||
Language: "en_US",
|
||||
Timezone: "UTC",
|
||||
EntryDirection: "asc",
|
||||
EntriesPerPage: 50,
|
||||
DisplayMode: "standalone",
|
||||
GestureNav: "tap",
|
||||
DefaultReadingSpeed: 35,
|
||||
CJKReadingSpeed: 25,
|
||||
DefaultHomePage: "unread",
|
||||
MediaPlaybackRate: 1.25,
|
||||
AlwaysOpenExternalLinks: true,
|
||||
}
|
||||
|
||||
err := settings.Validate()
|
||||
|
|
|
@ -23,29 +23,30 @@ func (h *handler) showSettingsPage(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
settingsForm := form.SettingsForm{
|
||||
Username: user.Username,
|
||||
Theme: user.Theme,
|
||||
Language: user.Language,
|
||||
Timezone: user.Timezone,
|
||||
EntryDirection: user.EntryDirection,
|
||||
EntryOrder: user.EntryOrder,
|
||||
EntriesPerPage: user.EntriesPerPage,
|
||||
KeyboardShortcuts: user.KeyboardShortcuts,
|
||||
ShowReadingTime: user.ShowReadingTime,
|
||||
CustomCSS: user.Stylesheet,
|
||||
CustomJS: user.CustomJS,
|
||||
ExternalFontHosts: user.ExternalFontHosts,
|
||||
EntrySwipe: user.EntrySwipe,
|
||||
GestureNav: user.GestureNav,
|
||||
DisplayMode: user.DisplayMode,
|
||||
DefaultReadingSpeed: user.DefaultReadingSpeed,
|
||||
CJKReadingSpeed: user.CJKReadingSpeed,
|
||||
DefaultHomePage: user.DefaultHomePage,
|
||||
CategoriesSortingOrder: user.CategoriesSortingOrder,
|
||||
MarkReadBehavior: form.MarkAsReadBehavior(user.MarkReadOnView, user.MarkReadOnMediaPlayerCompletion),
|
||||
MediaPlaybackRate: user.MediaPlaybackRate,
|
||||
BlockFilterEntryRules: user.BlockFilterEntryRules,
|
||||
KeepFilterEntryRules: user.KeepFilterEntryRules,
|
||||
Username: user.Username,
|
||||
Theme: user.Theme,
|
||||
Language: user.Language,
|
||||
Timezone: user.Timezone,
|
||||
EntryDirection: user.EntryDirection,
|
||||
EntryOrder: user.EntryOrder,
|
||||
EntriesPerPage: user.EntriesPerPage,
|
||||
KeyboardShortcuts: user.KeyboardShortcuts,
|
||||
ShowReadingTime: user.ShowReadingTime,
|
||||
CustomCSS: user.Stylesheet,
|
||||
CustomJS: user.CustomJS,
|
||||
ExternalFontHosts: user.ExternalFontHosts,
|
||||
EntrySwipe: user.EntrySwipe,
|
||||
GestureNav: user.GestureNav,
|
||||
DisplayMode: user.DisplayMode,
|
||||
DefaultReadingSpeed: user.DefaultReadingSpeed,
|
||||
CJKReadingSpeed: user.CJKReadingSpeed,
|
||||
DefaultHomePage: user.DefaultHomePage,
|
||||
CategoriesSortingOrder: user.CategoriesSortingOrder,
|
||||
MarkReadBehavior: form.MarkAsReadBehavior(user.MarkReadOnView, user.MarkReadOnMediaPlayerCompletion),
|
||||
MediaPlaybackRate: user.MediaPlaybackRate,
|
||||
BlockFilterEntryRules: user.BlockFilterEntryRules,
|
||||
KeepFilterEntryRules: user.KeepFilterEntryRules,
|
||||
AlwaysOpenExternalLinks: user.AlwaysOpenExternalLinks,
|
||||
}
|
||||
|
||||
timezones, err := h.store.Timezones()
|
||||
|
|
|
@ -88,6 +88,11 @@ func (h *handler) showUnreadCategoryEntryPage(w http.ResponseWriter, r *http.Req
|
|||
}
|
||||
}
|
||||
|
||||
if user.AlwaysOpenExternalLinks {
|
||||
html.Redirect(w, r, entry.URL)
|
||||
return
|
||||
}
|
||||
|
||||
sess := session.New(h.store, request.SessionID(r))
|
||||
view := view.New(h.tpl, r, sess)
|
||||
view.Set("entry", entry)
|
||||
|
|
|
@ -88,6 +88,11 @@ func (h *handler) showUnreadFeedEntryPage(w http.ResponseWriter, r *http.Request
|
|||
}
|
||||
}
|
||||
|
||||
if user.AlwaysOpenExternalLinks {
|
||||
html.Redirect(w, r, entry.URL)
|
||||
return
|
||||
}
|
||||
|
||||
sess := session.New(h.store, request.SessionID(r))
|
||||
view := view.New(h.tpl, r, sess)
|
||||
view.Set("entry", entry)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue