about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPaul Frazee <pfrazee@gmail.com>2023-08-08 15:54:36 -0700
committerGitHub <noreply@github.com>2023-08-08 15:54:36 -0700
commitbbe9861eef0e9f44b31259cb92221ee4094afac2 (patch)
tree2ddafcc3a9aa5fe19714203ea4bd616c3fcad4f9
parente51dbefd0ac1c04853237ed4889601da220f54ba (diff)
downloadvoidsky-bbe9861eef0e9f44b31259cb92221ee4094afac2.tar.zst
Add alerts to embeds (#1138)
* Add alerts to embeds

* Add images to the mock data

* Fix types
-rw-r--r--__e2e__/mock-server.ts4
-rw-r--r--jest/test-pds.ts27
-rw-r--r--src/lib/moderation.ts10
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx10
-rw-r--r--src/view/com/post/Post.tsx5
-rw-r--r--src/view/com/posts/FeedItem.tsx5
-rw-r--r--src/view/com/util/post-embeds/QuoteEmbed.tsx17
-rw-r--r--src/view/com/util/post-embeds/index.tsx17
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 && (
                 <ContentHider moderation={item.moderation.embed} style={s.mb10}>
-                  <PostEmbeds embed={item.post.embed} />
+                  <PostEmbeds
+                    embed={item.post.embed}
+                    moderation={item.moderation.embed}
+                  />
                 </ContentHider>
               )}
             </ContentHider>
@@ -428,7 +431,10 @@ export const PostThreadItem = observer(function PostThreadItem({
               ) : undefined}
               {item.post.embed && (
                 <ContentHider style={s.mb10} moderation={item.moderation.embed}>
-                  <PostEmbeds embed={item.post.embed} />
+                  <PostEmbeds
+                    embed={item.post.embed}
+                    moderation={item.moderation.embed}
+                  />
                 </ContentHider>
               )}
               {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 ? (
                 <ContentHider moderation={item.moderation.embed} style={s.mb10}>
-                  <PostEmbeds embed={item.post.embed} />
+                  <PostEmbeds
+                    embed={item.post.embed}
+                    moderation={item.moderation.embed}
+                  />
                 </ContentHider>
               ) : 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 ({
               <ContentHider
                 moderation={item.moderation.embed}
                 style={styles.embed}>
-                <PostEmbeds embed={item.post.embed} />
+                <PostEmbeds
+                  embed={item.post.embed}
+                  moderation={item.moderation.embed}
+                />
               </ContentHider>
             ) : 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<ViewStyle>
 }) {
   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<ViewStyle>
 }) {
   const pal = usePalette('default')
@@ -100,16 +107,19 @@ export function QuoteEmbed({
         postHref={itemHref}
         timestamp={quote.indexedAt}
       />
+      {moderation ? (
+        <PostAlerts moderation={moderation} style={styles.alert} />
+      ) : null}
       {!isEmpty ? (
         <Text type="post-text" style={pal.text} numberOfLines={6}>
           {quote.text}
         </Text>
       ) : null}
       {AppBskyEmbedImages.isView(imagesEmbed) && (
-        <PostEmbeds embed={imagesEmbed} />
+        <PostEmbeds embed={imagesEmbed} moderation={{}} />
       )}
       {AppBskyEmbedRecordWithMedia.isView(imagesEmbed) && (
-        <PostEmbeds embed={imagesEmbed.media} />
+        <PostEmbeds embed={imagesEmbed.media} moderation={{}} />
       )}
     </Link>
   )
@@ -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<ViewStyle>
 }) {
   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 (
       <View style={[styles.stackContainer, style]}>
-        <PostEmbeds embed={embed.media} />
-        <MaybeQuoteEmbed embed={embed.record} />
+        <PostEmbeds embed={embed.media} moderation={mediaModeration} />
+        <MaybeQuoteEmbed embed={embed.record} moderation={quoteModeration} />
       </View>
     )
   }
@@ -71,7 +80,9 @@ export function PostEmbeds({
 
     // quote post
     // =
-    return <MaybeQuoteEmbed embed={embed} style={style} />
+    return (
+      <MaybeQuoteEmbed embed={embed} style={style} moderation={moderation} />
+    )
   }
 
   // image embed