diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/api/index.ts | 105 | ||||
-rw-r--r-- | src/lib/link-meta/bsky.ts | 8 | ||||
-rw-r--r-- | src/lib/moderation.ts | 13 | ||||
-rw-r--r-- | src/lib/moderation/useModerationCauseDescription.ts | 27 |
4 files changed, 96 insertions, 57 deletions
diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index 658ed78de..94c8869a1 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -3,7 +3,7 @@ import { AppBskyEmbedImages, AppBskyEmbedRecord, AppBskyEmbedRecordWithMedia, - AppBskyFeedThreadgate, + AppBskyFeedPostgate, BskyAgent, ComAtprotoLabelDefs, RichText, @@ -11,7 +11,13 @@ import { import {AtUri} from '@atproto/api' import {logger} from '#/logger' -import {ThreadgateSetting} from '#/state/queries/threadgate' +import {writePostgateRecord} from '#/state/queries/postgate' +import { + createThreadgateRecord, + ThreadgateAllowUISetting, + threadgateAllowUISettingToAllowRecordValue, + writeThreadgateRecord, +} from '#/state/queries/threadgate' import {isNetworkError} from 'lib/strings/errors' import {shortenLinks, stripInvalidMentions} from 'lib/strings/rich-text-manip' import {isNative} from 'platform/detection' @@ -44,7 +50,8 @@ interface PostOpts { extLink?: ExternalEmbedDraft images?: ImageModel[] labels?: string[] - threadgate?: ThreadgateSetting[] + threadgate: ThreadgateAllowUISetting[] + postgate: AppBskyFeedPostgate.Record onStateChange?: (state: string) => void langs?: string[] } @@ -232,7 +239,9 @@ export async function post(agent: BskyAgent, opts: PostOpts) { labels, }) } catch (e: any) { - console.error(`Failed to create post: ${e.toString()}`) + logger.error(`Failed to create post`, { + safeMessage: e.message, + }) if (isNetworkError(e)) { throw new Error( 'Post failed to upload. Please check your Internet connection and try again.', @@ -242,56 +251,52 @@ export async function post(agent: BskyAgent, opts: PostOpts) { } } - try { - // TODO: this needs to be batch-created with the post! - if (opts.threadgate?.length) { - await createThreadgate(agent, res.uri, opts.threadgate) + if (opts.threadgate.some(tg => tg.type !== 'everybody')) { + try { + // TODO: this needs to be batch-created with the post! + await writeThreadgateRecord({ + agent, + postUri: res.uri, + threadgate: createThreadgateRecord({ + post: res.uri, + allow: threadgateAllowUISettingToAllowRecordValue(opts.threadgate), + }), + }) + } catch (e: any) { + logger.error(`Failed to create threadgate`, { + context: 'composer', + safeMessage: e.message, + }) + throw new Error( + 'Failed to save post interaction settings. Your post was created but users may be able to interact with it.', + ) } - } catch (e: any) { - console.error(`Failed to create threadgate: ${e.toString()}`) - throw new Error( - 'Post reply-controls failed to be set. Your post was created but anyone can reply to it.', - ) } - return res -} - -export async function createThreadgate( - agent: BskyAgent, - postUri: string, - threadgate: ThreadgateSetting[], -) { - let allow: ( - | AppBskyFeedThreadgate.MentionRule - | AppBskyFeedThreadgate.FollowingRule - | AppBskyFeedThreadgate.ListRule - )[] = [] - if (!threadgate.find(v => v.type === 'nobody')) { - for (const rule of threadgate) { - if (rule.type === 'mention') { - allow.push({$type: 'app.bsky.feed.threadgate#mentionRule'}) - } else if (rule.type === 'following') { - allow.push({$type: 'app.bsky.feed.threadgate#followingRule'}) - } else if (rule.type === 'list') { - allow.push({ - $type: 'app.bsky.feed.threadgate#listRule', - list: rule.list, - }) - } + if ( + opts.postgate.embeddingRules?.length || + opts.postgate.detachedEmbeddingUris?.length + ) { + try { + // TODO: this needs to be batch-created with the post! + await writePostgateRecord({ + agent, + postUri: res.uri, + postgate: { + ...opts.postgate, + post: res.uri, + }, + }) + } catch (e: any) { + logger.error(`Failed to create postgate`, { + context: 'composer', + safeMessage: e.message, + }) + throw new Error( + 'Failed to save post interaction settings. Your post was created but users may be able to interact with it.', + ) } } - const postUrip = new AtUri(postUri) - await agent.api.com.atproto.repo.putRecord({ - repo: agent.accountDid, - collection: 'app.bsky.feed.threadgate', - rkey: postUrip.rkey, - record: { - $type: 'app.bsky.feed.threadgate', - post: postUri, - allow, - createdAt: new Date().toISOString(), - }, - }) + return res } diff --git a/src/lib/link-meta/bsky.ts b/src/lib/link-meta/bsky.ts index e3b4ea0c9..3d49f5237 100644 --- a/src/lib/link-meta/bsky.ts +++ b/src/lib/link-meta/bsky.ts @@ -107,6 +107,11 @@ export async function extractBskyMeta( return meta } +export class EmbeddingDisabledError extends Error { + constructor() { + super('Embedding is disabled for this record') + } +} export async function getPostAsQuote( getPost: ReturnType<typeof useGetPost>, url: string, @@ -115,6 +120,9 @@ export async function getPostAsQuote( const [_0, user, _1, rkey] = url.split('/').filter(Boolean) const uri = makeRecordUri(user, 'app.bsky.feed.post', rkey) const post = await getPost({uri: uri}) + if (post.viewer?.embeddingDisabled) { + throw new EmbeddingDisabledError() + } return { uri: post.uri, cid: post.cid, diff --git a/src/lib/moderation.ts b/src/lib/moderation.ts index 4105c2c2d..3c96deecb 100644 --- a/src/lib/moderation.ts +++ b/src/lib/moderation.ts @@ -1,17 +1,20 @@ import { - ModerationCause, - ModerationUI, - InterpretedLabelValueDefinition, - LABELS, AppBskyLabelerDefs, BskyAgent, + InterpretedLabelValueDefinition, + LABELS, + ModerationCause, ModerationOpts, + ModerationUI, } from '@atproto/api' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' +import {AppModerationCause} from '#/components/Pills' -export function getModerationCauseKey(cause: ModerationCause): string { +export function getModerationCauseKey( + cause: ModerationCause | AppModerationCause, +): string { const source = cause.source.type === 'labeler' ? cause.source.did diff --git a/src/lib/moderation/useModerationCauseDescription.ts b/src/lib/moderation/useModerationCauseDescription.ts index 01ffbe5cf..9dce0b565 100644 --- a/src/lib/moderation/useModerationCauseDescription.ts +++ b/src/lib/moderation/useModerationCauseDescription.ts @@ -8,11 +8,13 @@ import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useLabelDefinitions} from '#/state/preferences' +import {useSession} from '#/state/session' import {CircleBanSign_Stroke2_Corner0_Rounded as CircleBanSign} from '#/components/icons/CircleBanSign' import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' import {Props as SVGIconProps} from '#/components/icons/common' import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash' import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning' +import {AppModerationCause} from '#/components/Pills' import {useGlobalLabelStrings} from './useGlobalLabelStrings' import {getDefinition, getLabelStrings} from './useLabelInfo' @@ -27,8 +29,9 @@ export interface ModerationCauseDescription { } export function useModerationCauseDescription( - cause: ModerationCause | undefined, + cause: ModerationCause | AppModerationCause | undefined, ): ModerationCauseDescription { + const {currentAccount} = useSession() const {_, i18n} = useLingui() const {labelDefs, labelers} = useLabelDefinitions() const globalLabelStrings = useGlobalLabelStrings() @@ -111,6 +114,18 @@ export function useModerationCauseDescription( description: _(msg`You have hidden this post`), } } + if (cause.type === 'reply-hidden') { + const isMe = currentAccount?.did === cause.source.did + return { + icon: EyeSlash, + name: isMe + ? _(msg`Reply Hidden by You`) + : _(msg`Reply Hidden by Thread Author`), + description: isMe + ? _(msg`You hid this reply.`) + : _(msg`The author of this thread has hidden this reply.`), + } + } if (cause.type === 'label') { const def = cause.labelDef || getDefinition(labelDefs, cause.label) const strings = getLabelStrings(i18n.locale, globalLabelStrings, def) @@ -150,5 +165,13 @@ export function useModerationCauseDescription( name: '', description: ``, } - }, [labelDefs, labelers, globalLabelStrings, cause, _, i18n.locale]) + }, [ + labelDefs, + labelers, + globalLabelStrings, + cause, + _, + i18n.locale, + currentAccount?.did, + ]) } |