For #26706 - Add sponsored urls filter in BlocklistHandler
This commit is contained in:
parent
070bf5ac24
commit
cedb777655
|
@ -170,9 +170,9 @@ fun AppState.filterState(blocklistHandler: BlocklistHandler): AppState =
|
|||
with(blocklistHandler) {
|
||||
copy(
|
||||
recentBookmarks = recentBookmarks.filteredByBlocklist(),
|
||||
recentTabs = recentTabs.filteredByBlocklist(),
|
||||
recentHistory = recentHistory.filteredByBlocklist(),
|
||||
recentSyncedTabState = recentSyncedTabState.filteredByBlocklist()
|
||||
recentTabs = recentTabs.filteredByBlocklist().filterContile(),
|
||||
recentHistory = recentHistory.filteredByBlocklist().filterContile(),
|
||||
recentSyncedTabState = recentSyncedTabState.filteredByBlocklist().filterContile()
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
|
||||
package org.mozilla.fenix.home.blocklist
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import mozilla.components.support.ktx.kotlin.sha1
|
||||
import org.mozilla.fenix.ext.containsQueryParameters
|
||||
import org.mozilla.fenix.home.recentbookmarks.RecentBookmark
|
||||
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTabState
|
||||
import org.mozilla.fenix.home.recenttabs.RecentTab
|
||||
|
@ -16,6 +18,8 @@ import org.mozilla.fenix.utils.Settings
|
|||
* Class for interacting with the a blocklist stored in [settings].
|
||||
* The blocklist is a set of SHA1 hashed URLs, which are stripped
|
||||
* of protocols and common subdomains like "www" or "mobile".
|
||||
*
|
||||
* Also used for filtering the sponsored URLs.
|
||||
*/
|
||||
class BlocklistHandler(private val settings: Settings) {
|
||||
|
||||
|
@ -52,6 +56,14 @@ class BlocklistHandler(private val settings: Settings) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a list of recent tabs from sponsored urls.
|
||||
*/
|
||||
@JvmName("filterContileRecentTab")
|
||||
fun List<RecentTab>.filterContile(): List<RecentTab> = filterNot {
|
||||
it is RecentTab.Tab &&
|
||||
Uri.parse(it.state.content.url).containsQueryParameters(settings.frecencyFilterQuery)
|
||||
}
|
||||
/**
|
||||
* If the state is set to [RecentSyncedTabState.Success], filter the list of recently synced
|
||||
* tabs by the blocklist. If the filtered list of tabs is empty, change the state to
|
||||
|
@ -74,6 +86,24 @@ class BlocklistHandler(private val settings: Settings) {
|
|||
this
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a list of recently synced tabs of sponsored urls if the state is
|
||||
* [RecentSyncedTabState.Success].
|
||||
*/
|
||||
@JvmName("filterContileRecentSyncedTab")
|
||||
fun RecentSyncedTabState.filterContile() = if (this is RecentSyncedTabState.Success) {
|
||||
val filteredTabs = this.tabs.filterNot {
|
||||
Uri.parse(it.url).containsQueryParameters(settings.frecencyFilterQuery)
|
||||
}
|
||||
if (filteredTabs.isEmpty()) {
|
||||
RecentSyncedTabState.None
|
||||
} else {
|
||||
RecentSyncedTabState.Success(filteredTabs)
|
||||
}
|
||||
} else {
|
||||
this
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a list of recent history items by the blocklist. Requires this class to be contextually
|
||||
* in a scope.
|
||||
|
@ -87,6 +117,15 @@ class BlocklistHandler(private val settings: Settings) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a list of recently visited history items of sponsored urls.
|
||||
*/
|
||||
@JvmName("filterContileRecentlyVisited")
|
||||
fun List<RecentlyVisitedItem>.filterContile(): List<RecentlyVisitedItem> = filterNot {
|
||||
it is RecentlyVisitedItem.RecentHistoryHighlight &&
|
||||
Uri.parse(it.url).containsQueryParameters(settings.frecencyFilterQuery)
|
||||
}
|
||||
|
||||
private fun blocklistContainsUrl(blocklist: Set<String>, url: String): Boolean =
|
||||
blocklist.any { it == url.stripAndHash() }
|
||||
}
|
||||
|
|
|
@ -41,14 +41,14 @@ class BlocklistMiddleware(
|
|||
is AppAction.Change -> {
|
||||
action.copy(
|
||||
recentBookmarks = action.recentBookmarks.filteredByBlocklist(),
|
||||
recentTabs = action.recentTabs.filteredByBlocklist(),
|
||||
recentHistory = action.recentHistory.filteredByBlocklist(),
|
||||
recentSyncedTabState = action.recentSyncedTabState.filteredByBlocklist()
|
||||
recentTabs = action.recentTabs.filteredByBlocklist().filterContile(),
|
||||
recentHistory = action.recentHistory.filteredByBlocklist().filterContile(),
|
||||
recentSyncedTabState = action.recentSyncedTabState.filteredByBlocklist().filterContile()
|
||||
)
|
||||
}
|
||||
is AppAction.RecentTabsChange -> {
|
||||
action.copy(
|
||||
recentTabs = action.recentTabs.filteredByBlocklist()
|
||||
recentTabs = action.recentTabs.filteredByBlocklist().filterContile()
|
||||
)
|
||||
}
|
||||
is AppAction.RecentBookmarksChange -> {
|
||||
|
@ -57,11 +57,11 @@ class BlocklistMiddleware(
|
|||
)
|
||||
}
|
||||
is AppAction.RecentHistoryChange -> {
|
||||
action.copy(recentHistory = action.recentHistory.filteredByBlocklist())
|
||||
action.copy(recentHistory = action.recentHistory.filteredByBlocklist().filterContile())
|
||||
}
|
||||
is AppAction.RecentSyncedTabStateChange -> {
|
||||
action.copy(
|
||||
state = action.state.filteredByBlocklist()
|
||||
state = action.state.filteredByBlocklist().filterContile()
|
||||
)
|
||||
}
|
||||
is AppAction.RemoveRecentTab -> {
|
||||
|
@ -97,14 +97,14 @@ class BlocklistMiddleware(
|
|||
private fun AppState.toActionFilteringAllState(blocklistHandler: BlocklistHandler) =
|
||||
with(blocklistHandler) {
|
||||
AppAction.Change(
|
||||
recentTabs = recentTabs.filteredByBlocklist(),
|
||||
recentTabs = recentTabs.filteredByBlocklist().filterContile(),
|
||||
recentBookmarks = recentBookmarks.filteredByBlocklist(),
|
||||
recentHistory = recentHistory.filteredByBlocklist(),
|
||||
recentHistory = recentHistory.filteredByBlocklist().filterContile(),
|
||||
topSites = topSites,
|
||||
mode = mode,
|
||||
collections = collections,
|
||||
showCollectionPlaceholder = showCollectionPlaceholder,
|
||||
recentSyncedTabState = recentSyncedTabState.filteredByBlocklist()
|
||||
recentSyncedTabState = recentSyncedTabState.filteredByBlocklist().filterContile()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,14 +5,20 @@ import io.mockk.mockk
|
|||
import io.mockk.slot
|
||||
import mozilla.components.browser.state.state.ContentState
|
||||
import mozilla.components.browser.state.state.TabSessionState
|
||||
import mozilla.components.concept.sync.DeviceType
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.home.recentbookmarks.RecentBookmark
|
||||
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab
|
||||
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTabState
|
||||
import org.mozilla.fenix.home.recenttabs.RecentTab
|
||||
import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
class BlocklistHandlerTest {
|
||||
private val mockSettings: Settings = mockk()
|
||||
|
||||
|
@ -117,4 +123,65 @@ class BlocklistHandlerTest {
|
|||
|
||||
assertEquals(listOf<String>(), filtered)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN recently synced tab is a sponsored url WHEN the tabs are filtered THEN the sponsored url be filtered`() {
|
||||
val blockedUrl = "test.com/?query=value"
|
||||
val mockSessionState: TabSessionState = mockk()
|
||||
val mockContent: ContentState = mockk()
|
||||
val tabs = RecentSyncedTabState.Success(
|
||||
listOf(
|
||||
RecentSyncedTab(
|
||||
"",
|
||||
DeviceType.DESKTOP,
|
||||
"title",
|
||||
blockedUrl,
|
||||
null
|
||||
)
|
||||
)
|
||||
)
|
||||
every { mockSessionState.content } returns mockContent
|
||||
every { mockContent.url } returns blockedUrl
|
||||
every { mockSettings.frecencyFilterQuery } returns "query=value"
|
||||
|
||||
val filtered = with(blocklistHandler) {
|
||||
tabs.filterContile()
|
||||
}
|
||||
|
||||
assertEquals(RecentSyncedTabState.None, filtered)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN recently visited item is a sponsored url WHEN the tabs are filtered THEN the sponsored url be filtered`() {
|
||||
val blockedUrl = "test.com/?query=value"
|
||||
val mockSessionState: TabSessionState = mockk()
|
||||
val mockContent: ContentState = mockk()
|
||||
val tabs = listOf(RecentlyVisitedItem.RecentHistoryHighlight("title", blockedUrl))
|
||||
every { mockSessionState.content } returns mockContent
|
||||
every { mockContent.url } returns blockedUrl
|
||||
every { mockSettings.frecencyFilterQuery } returns "query=value"
|
||||
|
||||
val filtered = with(blocklistHandler) {
|
||||
tabs.filterContile()
|
||||
}
|
||||
|
||||
assertEquals(listOf<String>(), filtered)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN recent tab is a sponsored url WHEN the tabs are filtered THEN the sponsored url be filtered`() {
|
||||
val blockedUrl = "test.com/?query=value"
|
||||
val mockSessionState: TabSessionState = mockk()
|
||||
val mockContent: ContentState = mockk()
|
||||
val tabs = listOf(RecentTab.Tab(mockSessionState))
|
||||
every { mockSessionState.content } returns mockContent
|
||||
every { mockContent.url } returns blockedUrl
|
||||
every { mockSettings.frecencyFilterQuery } returns "query=value"
|
||||
|
||||
val filtered = with(blocklistHandler) {
|
||||
tabs.filterContile()
|
||||
}
|
||||
|
||||
assertEquals(listOf<String>(), filtered)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,15 +14,18 @@ import mozilla.components.support.test.mock
|
|||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.components.AppStore
|
||||
import org.mozilla.fenix.components.appstate.AppAction
|
||||
import org.mozilla.fenix.components.appstate.AppState
|
||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||
import org.mozilla.fenix.home.recentbookmarks.RecentBookmark
|
||||
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTab
|
||||
import org.mozilla.fenix.home.recentsyncedtabs.RecentSyncedTabState
|
||||
import org.mozilla.fenix.home.recenttabs.RecentTab
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
|
||||
@RunWith(FenixRobolectricTestRunner::class)
|
||||
class BlocklistMiddlewareTest {
|
||||
private val mockSettings: Settings = mockk()
|
||||
private val blocklistHandler = BlocklistHandler(mockSettings)
|
||||
|
@ -178,6 +181,7 @@ class BlocklistMiddlewareTest {
|
|||
listOf(RecentTab.Tab(createTab(url = blockedUrl)), unblockedRecentTab)
|
||||
|
||||
every { mockSettings.homescreenBlocklist } returns setOf(blockedUrl.stripAndHash())
|
||||
every { mockSettings.frecencyFilterQuery } returns ""
|
||||
val middleware = BlocklistMiddleware(blocklistHandler)
|
||||
val store = AppStore(
|
||||
AppState(),
|
||||
|
@ -328,6 +332,7 @@ class BlocklistMiddlewareTest {
|
|||
)
|
||||
|
||||
every { mockSettings.homescreenBlocklist } returns setOf(blockedHost.stripAndHash())
|
||||
every { mockSettings.frecencyFilterQuery } returns ""
|
||||
val middleware = BlocklistMiddleware(blocklistHandler)
|
||||
val store = AppStore(
|
||||
AppState(),
|
||||
|
@ -435,6 +440,7 @@ class BlocklistMiddlewareTest {
|
|||
val updateSlot = slot<Set<String>>()
|
||||
every { mockSettings.homescreenBlocklist = capture(updateSlot) } returns Unit
|
||||
every { mockSettings.homescreenBlocklist } returns setOf(tabUrls[0].stripAndHash())
|
||||
every { mockSettings.frecencyFilterQuery } returns ""
|
||||
|
||||
store.dispatch(
|
||||
AppAction.RemoveRecentSyncedTab(
|
||||
|
|
Loading…
Reference in New Issue