From bbe9861eef0e9f44b31259cb92221ee4094afac2 Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Tue, 8 Aug 2023 15:54:36 -0700 Subject: Add alerts to embeds (#1138) * Add alerts to embeds * Add images to the mock data * Fix types --- __e2e__/mock-server.ts | 4 ++-- jest/test-pds.ts | 27 +++++++++++++++++++++++---- src/lib/moderation.ts | 10 ++++++++++ src/view/com/post-thread/PostThreadItem.tsx | 10 ++++++++-- src/view/com/post/Post.tsx | 5 ++++- src/view/com/posts/FeedItem.tsx | 5 ++++- src/view/com/util/post-embeds/QuoteEmbed.tsx | 17 +++++++++++++++-- src/view/com/util/post-embeds/index.tsx | 17 ++++++++++++++--- 8 files changed, 80 insertions(+), 15 deletions(-) diff --git a/__e2e__/mock-server.ts b/__e2e__/mock-server.ts index 79c318571..0a97dbcd2 100644 --- a/__e2e__/mock-server.ts +++ b/__e2e__/mock-server.ts @@ -144,7 +144,7 @@ async function main() { await server.mocker.labelProfile('porn', 'porn-profile') await server.mocker.labelPost( 'porn', - await server.mocker.createPost('porn-posts', 'porn post'), + await server.mocker.createImagePost('porn-posts', 'porn post'), ) await server.mocker.labelPost( 'porn', @@ -167,7 +167,7 @@ async function main() { await server.mocker.labelProfile('nudity', 'nudity-profile') await server.mocker.labelPost( 'nudity', - await server.mocker.createPost('nudity-posts', 'nudity post'), + await server.mocker.createImagePost('nudity-posts', 'nudity post'), ) await server.mocker.labelPost( 'nudity', diff --git a/jest/test-pds.ts b/jest/test-pds.ts index 21d90b93b..48b73e848 100644 --- a/jest/test-pds.ts +++ b/jest/test-pds.ts @@ -29,13 +29,13 @@ export async function createServer( plc: {port: port2}, }) - const profilePic = fs.readFileSync( + const pic = fs.readFileSync( path.join(__dirname, '..', 'assets', 'default-avatar.jpg'), ) return { pdsUrl, - mocker: new Mocker(pds, pdsUrl, profilePic), + mocker: new Mocker(pds, pdsUrl, pic), async close() { await pds.server.destroy() await plc.server.destroy() @@ -50,7 +50,7 @@ class Mocker { constructor( public pds: DevEnvTestPDS, public service: string, - public profilePic: Uint8Array, + public pic: Uint8Array, ) { this.agent = new BskyAgent({service}) } @@ -90,7 +90,7 @@ class Mocker { password: 'hunter2', }) await agent.upsertProfile(async () => { - const blob = await agent.uploadBlob(this.profilePic, { + const blob = await agent.uploadBlob(this.pic, { encoding: 'image/jpeg', }) return { @@ -151,6 +151,25 @@ class Mocker { }) } + async createImagePost(user: string, text: string) { + const agent = this.users[user]?.agent + if (!agent) { + throw new Error(`Not a user: ${user}`) + } + const blob = await agent.uploadBlob(this.pic, { + encoding: 'image/jpeg', + }) + return await agent.post({ + text, + langs: ['en'], + embed: { + $type: 'app.bsky.embed.images', + images: [{image: blob.data.blob, alt: ''}], + }, + createdAt: new Date().toISOString(), + }) + } + async createQuotePost( user: string, text: string, diff --git a/src/lib/moderation.ts b/src/lib/moderation.ts index 758e3de3a..1ed830fd8 100644 --- a/src/lib/moderation.ts +++ b/src/lib/moderation.ts @@ -75,3 +75,13 @@ export function getProfileModerationCauses( return true }) as ModerationCause[] } + +export function isCauseALabelOnUri( + cause: ModerationCause | undefined, + uri: string, +): boolean { + if (cause?.type !== 'label') { + return false + } + return cause.label.uri === uri +} diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index c7b5711c0..b71d6bdcf 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -269,7 +269,10 @@ export const PostThreadItem = observer(function PostThreadItem({ ) : undefined} {item.post.embed && ( - + )} @@ -428,7 +431,10 @@ export const PostThreadItem = observer(function PostThreadItem({ ) : undefined} {item.post.embed && ( - + )} {needsTranslation && ( diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index f6873b0a0..bf9437076 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -267,7 +267,10 @@ const PostLoaded = observer( ) : undefined} {item.post.embed ? ( - + ) : null} {needsTranslation && ( diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index eecb4c533..bed3d3a61 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -293,7 +293,10 @@ export const FeedItem = observer(function ({ - + ) : null} {needsTranslation && ( diff --git a/src/view/com/util/post-embeds/QuoteEmbed.tsx b/src/view/com/util/post-embeds/QuoteEmbed.tsx index 9f11fe48c..f82b5b7df 100644 --- a/src/view/com/util/post-embeds/QuoteEmbed.tsx +++ b/src/view/com/util/post-embeds/QuoteEmbed.tsx @@ -5,6 +5,7 @@ import { AppBskyFeedPost, AppBskyEmbedImages, AppBskyEmbedRecordWithMedia, + ModerationUI, } from '@atproto/api' import {AtUri} from '@atproto/api' import {PostMeta} from '../PostMeta' @@ -13,14 +14,17 @@ import {Text} from '../text/Text' import {usePalette} from 'lib/hooks/usePalette' import {ComposerOptsQuote} from 'state/models/ui/shell' import {PostEmbeds} from '.' +import {PostAlerts} from '../moderation/PostAlerts' import {makeProfileLink} from 'lib/routes/links' import {InfoCircleIcon} from 'lib/icons' export function MaybeQuoteEmbed({ embed, + moderation, style, }: { embed: AppBskyEmbedRecord.View + moderation: ModerationUI style?: StyleProp }) { const pal = usePalette('default') @@ -39,6 +43,7 @@ export function MaybeQuoteEmbed({ text: embed.record.value.text, embeds: embed.record.embeds, }} + moderation={moderation} style={style} /> ) @@ -66,9 +71,11 @@ export function MaybeQuoteEmbed({ export function QuoteEmbed({ quote, + moderation, style, }: { quote: ComposerOptsQuote + moderation?: ModerationUI style?: StyleProp }) { const pal = usePalette('default') @@ -100,16 +107,19 @@ export function QuoteEmbed({ postHref={itemHref} timestamp={quote.indexedAt} /> + {moderation ? ( + + ) : null} {!isEmpty ? ( {quote.text} ) : null} {AppBskyEmbedImages.isView(imagesEmbed) && ( - + )} {AppBskyEmbedRecordWithMedia.isView(imagesEmbed) && ( - + )} ) @@ -140,4 +150,7 @@ const styles = StyleSheet.create({ paddingHorizontal: 14, borderWidth: 1, }, + alert: { + marginBottom: 6, + }, }) diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx index 32e92119d..b1c1c6a2e 100644 --- a/src/view/com/util/post-embeds/index.tsx +++ b/src/view/com/util/post-embeds/index.tsx @@ -14,6 +14,7 @@ import { AppBskyEmbedRecordWithMedia, AppBskyFeedDefs, AppBskyGraphDefs, + ModerationUI, } from '@atproto/api' import {Link} from '../Link' import {ImageLayoutGrid} from '../images/ImageLayoutGrid' @@ -28,6 +29,7 @@ import {AutoSizedImage} from '../images/AutoSizedImage' import {CustomFeedEmbed} from './CustomFeedEmbed' import {ListEmbed} from './ListEmbed' import {isDesktopWeb} from 'platform/detection' +import {isCauseALabelOnUri} from 'lib/moderation' type Embed = | AppBskyEmbedRecord.View @@ -38,9 +40,11 @@ type Embed = export function PostEmbeds({ embed, + moderation, style, }: { embed?: Embed + moderation: ModerationUI style?: StyleProp }) { const pal = usePalette('default') @@ -49,10 +53,15 @@ export function PostEmbeds({ // quote post with media // = if (AppBskyEmbedRecordWithMedia.isView(embed)) { + const isModOnQuote = + AppBskyEmbedRecord.isViewRecord(embed.record.record) && + isCauseALabelOnUri(moderation.cause, embed.record.record.uri) + const mediaModeration = isModOnQuote ? {} : moderation + const quoteModeration = isModOnQuote ? moderation : {} return ( - - + + ) } @@ -71,7 +80,9 @@ export function PostEmbeds({ // quote post // = - return + return ( + + ) } // image embed -- cgit 1.4.1