Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle nsfw feeds in public view #2035

Merged
merged 10 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/locale/locales/cs/messages.js

Large diffs are not rendered by default.

236 changes: 130 additions & 106 deletions src/locale/locales/cs/messages.po

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/locale/locales/en/messages.js

Large diffs are not rendered by default.

236 changes: 130 additions & 106 deletions src/locale/locales/en/messages.po

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/locale/locales/es/messages.js

Large diffs are not rendered by default.

236 changes: 130 additions & 106 deletions src/locale/locales/es/messages.po

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/locale/locales/fr/messages.js

Large diffs are not rendered by default.

236 changes: 130 additions & 106 deletions src/locale/locales/fr/messages.po

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/locale/locales/hi/messages.js

Large diffs are not rendered by default.

236 changes: 130 additions & 106 deletions src/locale/locales/hi/messages.po

Large diffs are not rendered by default.

38 changes: 37 additions & 1 deletion src/state/queries/post-feed.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {AppBskyFeedDefs, AppBskyFeedPost} from '@atproto/api'
import {AppBskyFeedDefs, AppBskyFeedPost, moderatePost} from '@atproto/api'
import {
useInfiniteQuery,
InfiniteData,
Expand All @@ -18,6 +18,10 @@ import {MergeFeedAPI} from 'lib/api/feed/merge'
import {logger} from '#/logger'
import {STALE} from '#/state/queries'
import {precacheFeedPosts as precacheResolvedUris} from './resolve-uri'
import {getAgent} from '#/state/session'
import {DEFAULT_LOGGED_OUT_PREFERENCES} from '#/state/queries/preferences/const'
import {getModerationOpts} from '#/state/queries/preferences/moderation'
import {KnownError} from '#/view/com/posts/FeedErrorMessage'

type ActorDid = string
type AuthorFilter =
Expand Down Expand Up @@ -103,6 +107,38 @@ export function usePostFeedQuery(
const res = await api.fetch({cursor, limit: 30})
precacheResolvedUris(queryClient, res.feed) // precache the handle->did resolution
const slices = tuner.tune(res.feed)

/*
* If this is a public view, we need to check if posts fail moderation.
* If all fail, we throw an error. If only some fail, we continue and let
* moderations happen later, which results in some posts being shown and
* some not.
*/
if (!getAgent().session) {
// assume false
let somePostsPassModeration = false

for (const slice of slices) {
for (let i = 0; i < slice.items.length; i++) {
const item = slice.items[i]
const moderationOpts = getModerationOpts({
userDid: '',
preferences: DEFAULT_LOGGED_OUT_PREFERENCES,
})
const moderation = moderatePost(item.post, moderationOpts)

if (!moderation.content.filter) {
// we have a sfw post
somePostsPassModeration = true
}
}
}

if (!somePostsPassModeration) {
throw new Error(KnownError.FeedNSFPublic)
}
}

return {
api,
tuner,
Expand Down
102 changes: 69 additions & 33 deletions src/view/com/posts/FeedErrorMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,15 @@ import {EmptyState} from '../util/EmptyState'
import {cleanError} from '#/lib/strings/errors'
import {useRemoveFeedMutation} from '#/state/queries/preferences'

enum KnownError {
Block,
FeedgenDoesNotExist,
FeedgenMisconfigured,
FeedgenBadResponse,
FeedgenOffline,
FeedgenUnknown,
Unknown,
}

const MESSAGES = {
[KnownError.Unknown]: '',
[KnownError.Block]: '',
[KnownError.FeedgenDoesNotExist]: `Hmmm, we're having trouble finding this feed. It may have been deleted.`,
[KnownError.FeedgenMisconfigured]:
'Hmm, the feed server appears to be misconfigured. Please let the feed owner know about this issue.',
[KnownError.FeedgenBadResponse]:
'Hmm, the feed server gave a bad response. Please let the feed owner know about this issue.',
[KnownError.FeedgenOffline]:
'Hmm, the feed server appears to be offline. Please let the feed owner know about this issue.',
[KnownError.FeedgenUnknown]:
'Hmm, some kind of issue occured when contacting the feed server. Please let the feed owner know about this issue.',
export enum KnownError {
Block = 'Block',
FeedgenDoesNotExist = 'FeedgenDoesNotExist',
FeedgenMisconfigured = 'FeedgenMisconfigured',
FeedgenBadResponse = 'FeedgenBadResponse',
FeedgenOffline = 'FeedgenOffline',
FeedgenUnknown = 'FeedgenUnknown',
FeedNSFPublic = 'FeedNSFPublic',
Unknown = 'Unknown',
}

export function FeedErrorMessage({
Expand Down Expand Up @@ -90,7 +77,32 @@ function FeedgenErrorMessage({
const pal = usePalette('default')
const {_: _l} = useLingui()
const navigation = useNavigation<NavigationProp>()
const msg = MESSAGES[knownError]
const msg = React.useMemo(
() =>
({
[KnownError.Unknown]: '',
[KnownError.Block]: '',
[KnownError.FeedgenDoesNotExist]: _l(
msgLingui`Hmmm, we're having trouble finding this feed. It may have been deleted.`,
),
[KnownError.FeedgenMisconfigured]: _l(
msgLingui`Hmm, the feed server appears to be misconfigured. Please let the feed owner know about this issue.`,
),
[KnownError.FeedgenBadResponse]: _l(
msgLingui`Hmm, the feed server gave a bad response. Please let the feed owner know about this issue.`,
),
[KnownError.FeedgenOffline]: _l(
msgLingui`Hmm, the feed server appears to be offline. Please let the feed owner know about this issue.`,
),
[KnownError.FeedNSFPublic]: _l(
msgLingui`We're sorry, but this content is not viewable without a Bluesky account.`,
),
[KnownError.FeedgenUnknown]: _l(
msgLingui`Hmm, some kind of issue occured when contacting the feed server. Please let the feed owner know about this issue.`,
),
}[knownError]),
[_l, knownError],
)
const [_, uri] = feedDesc.split('|')
const [ownerDid] = safeParseFeedgenUri(uri)
const {openModal, closeModal} = useModalControls()
Expand Down Expand Up @@ -121,6 +133,36 @@ function FeedgenErrorMessage({
})
}, [openModal, closeModal, uri, removeFeed, _l])

const cta = React.useMemo(() => {
switch (knownError) {
case KnownError.FeedNSFPublic: {
return null
}
case KnownError.FeedgenDoesNotExist:
case KnownError.FeedgenMisconfigured:
case KnownError.FeedgenBadResponse:
case KnownError.FeedgenOffline:
case KnownError.FeedgenUnknown: {
return (
<View style={{flexDirection: 'row', alignItems: 'center', gap: 10}}>
{knownError === KnownError.FeedgenDoesNotExist && (
<Button
type="inverted"
label="Remove feed"
onPress={onRemoveFeed}
/>
)}
<Button
type="default-light"
label="View profile"
onPress={onViewProfile}
/>
</View>
)
}
}
}, [knownError, onViewProfile, onRemoveFeed])

return (
<View
style={[
Expand All @@ -134,16 +176,7 @@ function FeedgenErrorMessage({
},
]}>
<Text style={pal.text}>{msg}</Text>
<View style={{flexDirection: 'row', alignItems: 'center', gap: 10}}>
{knownError === KnownError.FeedgenDoesNotExist && (
<Button type="inverted" label="Remove feed" onPress={onRemoveFeed} />
)}
<Button
type="default-light"
label="View profile"
onPress={onViewProfile}
/>
</View>
{cta}
</View>
)
}
Expand Down Expand Up @@ -196,5 +229,8 @@ function detectKnownError(
if (error.includes('feed provided an invalid response')) {
return KnownError.FeedgenBadResponse
}
if (error.includes(KnownError.FeedNSFPublic)) {
return KnownError.FeedNSFPublic
}
return KnownError.FeedgenUnknown
}