mirror of
https://github.com/miniflux/v2.git
synced 2025-06-27 16:36:00 +00:00
feat: add entry filters at the feed level
This commit is contained in:
parent
cb59944d6b
commit
2a9d91c783
37 changed files with 513 additions and 350 deletions
|
@ -21,36 +21,42 @@ const (
|
|||
)
|
||||
|
||||
func IsBlockedEntry(feed *model.Feed, entry *model.Entry, user *model.User) bool {
|
||||
// Check user-defined block rules first
|
||||
if user.BlockFilterEntryRules != "" {
|
||||
if matchesUserRules(user.BlockFilterEntryRules, entry, feed, filterActionBlock) {
|
||||
if matchesEntryFilterRules(user.BlockFilterEntryRules, entry, feed, filterActionBlock) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if feed.BlockFilterEntryRules != "" {
|
||||
if matchesEntryFilterRules(feed.BlockFilterEntryRules, entry, feed, filterActionBlock) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Check feed-level blocklist rules
|
||||
if feed.BlocklistRules == "" {
|
||||
return false
|
||||
}
|
||||
|
||||
return matchesFeedRules(feed.BlocklistRules, entry, feed, filterActionBlock)
|
||||
return matchesEntryRegexRules(feed.BlocklistRules, entry, feed, filterActionBlock)
|
||||
}
|
||||
|
||||
func IsAllowedEntry(feed *model.Feed, entry *model.Entry, user *model.User) bool {
|
||||
// Check user-defined keep rules first
|
||||
if user.KeepFilterEntryRules != "" {
|
||||
return matchesUserRules(user.KeepFilterEntryRules, entry, feed, filterActionAllow)
|
||||
return matchesEntryFilterRules(user.KeepFilterEntryRules, entry, feed, filterActionAllow)
|
||||
}
|
||||
|
||||
if feed.KeepFilterEntryRules != "" {
|
||||
return matchesEntryFilterRules(feed.KeepFilterEntryRules, entry, feed, filterActionAllow)
|
||||
}
|
||||
|
||||
// Check feed-level keeplist rules
|
||||
if feed.KeeplistRules == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
return matchesFeedRules(feed.KeeplistRules, entry, feed, filterActionAllow)
|
||||
return matchesEntryRegexRules(feed.KeeplistRules, entry, feed, filterActionAllow)
|
||||
}
|
||||
|
||||
func matchesUserRules(rules string, entry *model.Entry, feed *model.Feed, filterAction filterActionType) bool {
|
||||
func matchesEntryFilterRules(rules string, entry *model.Entry, feed *model.Feed, filterAction filterActionType) bool {
|
||||
for rule := range strings.SplitSeq(rules, "\n") {
|
||||
if matchesRule(rule, entry) {
|
||||
logFilterAction(entry, feed, rule, filterAction)
|
||||
|
@ -60,10 +66,10 @@ func matchesUserRules(rules string, entry *model.Entry, feed *model.Feed, filter
|
|||
return false
|
||||
}
|
||||
|
||||
func matchesFeedRules(rules string, entry *model.Entry, feed *model.Feed, filterAction filterActionType) bool {
|
||||
func matchesEntryRegexRules(rules string, entry *model.Entry, feed *model.Feed, filterAction filterActionType) bool {
|
||||
compiledRegex, err := regexp.Compile(rules)
|
||||
if err != nil {
|
||||
slog.Debug("Failed on regexp compilation",
|
||||
slog.Warn("Failed on regexp compilation",
|
||||
slog.String("pattern", rules),
|
||||
slog.Any("error", err),
|
||||
)
|
||||
|
|
|
@ -41,6 +41,7 @@ func TestBlockingEntries(t *testing.T) {
|
|||
{&model.Feed{ID: 1}, &model.Entry{Author: "Different", Tags: []string{"example", "test"}}, &model.User{BlockFilterEntryRules: "EntryAuthor\nEntryTag=(?i)Test"}, true},
|
||||
{&model.Feed{ID: 1}, &model.Entry{Date: time.Date(2024, 3, 14, 0, 0, 0, 0, time.UTC)}, &model.User{BlockFilterEntryRules: "EntryDate=before:2024-03-15"}, true},
|
||||
{&model.Feed{ID: 1}, &model.Entry{Date: time.Date(2024, 3, 14, 0, 0, 0, 0, time.UTC)}, &model.User{BlockFilterEntryRules: "UnknownRuleType=test"}, false},
|
||||
{&model.Feed{ID: 1, BlockFilterEntryRules: "EntryURL=(?i)example\nEntryTitle=(?i)Test"}, &model.Entry{URL: "https://example.com", Title: "Some Example"}, &model.User{}, true},
|
||||
}
|
||||
|
||||
for _, tc := range scenarios {
|
||||
|
@ -93,6 +94,7 @@ func TestAllowEntries(t *testing.T) {
|
|||
{&model.Feed{ID: 1}, &model.Entry{Date: time.Date(2024, 2, 28, 0, 0, 0, 0, time.UTC)}, &model.User{KeepFilterEntryRules: "EntryDate=between:2024-03-15"}, false}, // missing second date in range
|
||||
{&model.Feed{ID: 1}, &model.Entry{Date: time.Date(2024, 2, 28, 0, 0, 0, 0, time.UTC)}, &model.User{KeepFilterEntryRules: "EntryDate=abcd"}, false}, // no colon in rule value
|
||||
{&model.Feed{ID: 1}, &model.Entry{Date: time.Date(2024, 2, 28, 0, 0, 0, 0, time.UTC)}, &model.User{KeepFilterEntryRules: "EntryDate=unknown:2024-03-15"}, false}, // unknown rule type
|
||||
{&model.Feed{ID: 1, KeepFilterEntryRules: "EntryURL=(?i)example\nEntryTitle=(?i)Test"}, &model.Entry{URL: "https://example.com", Title: "Some Example"}, &model.User{}, true},
|
||||
}
|
||||
|
||||
for _, tc := range scenarios {
|
||||
|
|
|
@ -61,6 +61,8 @@ func CreateFeedFromSubscriptionDiscovery(store *storage.Storage, userID int64, f
|
|||
subscription.BlocklistRules = feedCreationRequest.BlocklistRules
|
||||
subscription.KeeplistRules = feedCreationRequest.KeeplistRules
|
||||
subscription.UrlRewriteRules = feedCreationRequest.UrlRewriteRules
|
||||
subscription.BlockFilterEntryRules = feedCreationRequest.BlockFilterEntryRules
|
||||
subscription.KeepFilterEntryRules = feedCreationRequest.KeepFilterEntryRules
|
||||
subscription.EtagHeader = feedCreationRequest.ETag
|
||||
subscription.LastModifiedHeader = feedCreationRequest.LastModified
|
||||
subscription.FeedURL = feedCreationRequest.FeedURL
|
||||
|
@ -158,9 +160,11 @@ func CreateFeed(store *storage.Storage, userID int64, feedCreationRequest *model
|
|||
subscription.FetchViaProxy = feedCreationRequest.FetchViaProxy
|
||||
subscription.ScraperRules = feedCreationRequest.ScraperRules
|
||||
subscription.RewriteRules = feedCreationRequest.RewriteRules
|
||||
subscription.UrlRewriteRules = feedCreationRequest.UrlRewriteRules
|
||||
subscription.BlocklistRules = feedCreationRequest.BlocklistRules
|
||||
subscription.KeeplistRules = feedCreationRequest.KeeplistRules
|
||||
subscription.UrlRewriteRules = feedCreationRequest.UrlRewriteRules
|
||||
subscription.BlockFilterEntryRules = feedCreationRequest.BlockFilterEntryRules
|
||||
subscription.KeepFilterEntryRules = feedCreationRequest.KeepFilterEntryRules
|
||||
subscription.HideGlobally = feedCreationRequest.HideGlobally
|
||||
subscription.EtagHeader = responseHandler.ETag()
|
||||
subscription.LastModifiedHeader = responseHandler.LastModified()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue