Skip to content

Commit

Permalink
Refactor, new approach
Browse files Browse the repository at this point in the history
  • Loading branch information
estrattonbailey committed Nov 30, 2023
1 parent 5c099e7 commit d744290
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 87 deletions.
39 changes: 38 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 @@ -87,6 +91,7 @@ export function usePostFeedQuery(
>({
staleTime: STALE.INFINITY,
queryKey: RQKEY(feedDesc, params),
retry: false,
async queryFn({pageParam}: {pageParam: RQPageParam}) {
logger.debug('usePostFeedQuery', {feedDesc, pageParam})

Expand All @@ -103,6 +108,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
79 changes: 14 additions & 65 deletions src/view/com/posts/Feed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
View,
ViewStyle,
} from 'react-native'
import {PostModeration, moderatePost} from '@atproto/api'
import {FlatList} from '../util/Views'
import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
import {FeedErrorMessage} from './FeedErrorMessage'
Expand All @@ -28,8 +27,6 @@ import {
} from '#/state/queries/post-feed'
import {useModerationOpts} from '#/state/queries/preferences'
import {FeedPostSlice} from '#/state/queries/post-feed'
import {Text} from '#/view/com/util/text/Text'
import {Trans} from '@lingui/macro'

type FeedItem =
| {
Expand All @@ -47,10 +44,6 @@ type FeedItem =
| {
_reactKey: '__feed_slice__'
slice: FeedPostSlice
moderations: PostModeration[]
}
| {
_reactKey: '__authed_only__'
}

let Feed = ({
Expand Down Expand Up @@ -149,32 +142,14 @@ let Feed = ({

for (const page of data?.pages) {
slices = slices.concat(
page.slices
.map(slice => ({
_reactKey: '__feed_slice__',
slice,
moderations: slice.items.map(item =>
moderatePost(item.post, moderationOpts),
),
}))
.filter(item => {
for (let i = 0; i < item.slice.items.length; i++) {
if (item.moderations[i]?.content.filter) {
return false
}
}

return true
}) as FeedItem[],
page.slices.map(slice => ({
_reactKey: '__feed_slice__',
slice,
})),
)
}

if (slices.length) {
arr = arr.concat(slices)
} else {
isFeedDisabledRef.current = true
arr.push({_reactKey: '__authed_only__'})
}
arr = arr.concat(slices)
}
if (isError && !isEmpty) {
arr = arr.concat([{_reactKey: '__load_more_error__'}])
Expand Down Expand Up @@ -248,14 +223,19 @@ let Feed = ({
} else if (item._reactKey === '__loading__') {
return <PostFeedLoadingPlaceholder />
} else if (item._reactKey === '__feed_slice__') {
return <FeedSlice slice={item.slice} moderations={item.moderations} />
} else if (item._reactKey === '__authed_only__') {
return <AuthedOnlyFeedFallback />
return <FeedSlice slice={item.slice} moderationOpts={moderationOpts!} />
} else {
return null
}
},
[feed, error, onPressTryAgain, onPressRetryLoadMore, renderEmptyState],
[
feed,
error,
onPressTryAgain,
onPressRetryLoadMore,
renderEmptyState,
moderationOpts,
],
)

const shouldRenderEndOfFeed =
Expand Down Expand Up @@ -320,34 +300,3 @@ export {Feed}
const styles = StyleSheet.create({
feedFooter: {paddingTop: 20},
})

function AuthedOnlyFeedFallback() {
const pal = usePalette('default')
return (
<View
style={[
pal.border,
{
padding: 18,
borderTopWidth: 1,
minHeight: Dimensions.get('window').height * 1.5,
},
]}>
<View
style={[
pal.viewLight,
{
padding: 12,
borderRadius: 8,
},
]}>
<Text style={[pal.text]}>
<Trans>
We're sorry, but this content is not viewable without a Bluesky
account.
</Trans>
</Text>
</View>
</View>
)
}
63 changes: 45 additions & 18 deletions src/view/com/posts/FeedErrorMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +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,
export enum KnownError {
Block = 'Block',
FeedgenDoesNotExist = 'FeedgenDoesNotExist',
FeedgenMisconfigured = 'FeedgenMisconfigured',
FeedgenBadResponse = 'FeedgenBadResponse',
FeedgenOffline = 'FeedgenOffline',
FeedgenUnknown = 'FeedgenUnknown',
FeedNSFPublic = 'FeedNSFPublic',
Unknown = 'Unknown',
}

const MESSAGES = {
Expand All @@ -37,6 +38,8 @@ const MESSAGES = {
'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.FeedNSFPublic]:
'Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!',
[KnownError.FeedgenUnknown]:
'Hmm, some kind of issue occured when contacting the feed server. Please let the feed owner know about this issue.',
}
Expand Down Expand Up @@ -121,6 +124,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 +167,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 +220,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
}
22 changes: 19 additions & 3 deletions src/view/com/posts/FeedSlice.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {memo} from 'react'
import {StyleSheet, View} from 'react-native'
import {FeedPostSlice} from '#/state/queries/post-feed'
import {AtUri, PostModeration} from '@atproto/api'
import {AtUri, moderatePost, ModerationOpts} from '@atproto/api'
import {Link} from '../util/Link'
import {Text} from '../util/text/Text'
import Svg, {Circle, Line} from 'react-native-svg'
Expand All @@ -11,11 +11,27 @@ import {makeProfileLink} from 'lib/routes/links'

let FeedSlice = ({
slice,
moderations,
ignoreFilterFor,
moderationOpts,
}: {
slice: FeedPostSlice
moderations: PostModeration[]
ignoreFilterFor?: string
moderationOpts: ModerationOpts
}): React.ReactNode => {
const moderations = React.useMemo(() => {
return slice.items.map(item => moderatePost(item.post, moderationOpts))
}, [slice, moderationOpts])

// apply moderation filter
for (let i = 0; i < slice.items.length; i++) {
if (
moderations[i]?.content.filter &&
slice.items[i].post.author.did !== ignoreFilterFor
) {
return null
}
}

if (slice.isThread && slice.items.length > 3) {
const last = slice.items.length - 1
return (
Expand Down

0 comments on commit d744290

Please sign in to comment.