Bluesky app fork with some witchin' additions 💫

Add validation to threadgate records, check for max hidden replies (#9178)

authored by

Eric Bailey and committed by
GitHub
5bf1141b e1ee8562

+64 -5
+30 -5
src/components/PostControls/PostMenu/PostMenuItems.tsx
··· 46 46 useProfileBlockMutationQueue, 47 47 useProfileMuteMutationQueue, 48 48 } from '#/state/queries/profile' 49 - import {useToggleReplyVisibilityMutation} from '#/state/queries/threadgate' 49 + import { 50 + InvalidInteractionSettingsError, 51 + MAX_HIDDEN_REPLIES, 52 + MaxHiddenRepliesError, 53 + useToggleReplyVisibilityMutation, 54 + } from '#/state/queries/threadgate' 50 55 import {useRequireAuth, useSession} from '#/state/session' 51 56 import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies' 52 57 import * as Toast from '#/view/com/util/Toast' ··· 339 344 : _(msg({message: 'Reply visibility updated', context: 'toast'})), 340 345 ) 341 346 } catch (e: any) { 342 - Toast.show( 343 - _(msg({message: 'Updating reply visibility failed', context: 'toast'})), 344 - ) 345 - logger.error(`Failed to ${action} reply`, {safeMessage: e.message}) 347 + if (e instanceof MaxHiddenRepliesError) { 348 + Toast.show( 349 + _( 350 + msg({ 351 + message: `You can hide a maximum of ${MAX_HIDDEN_REPLIES} replies.`, 352 + context: 'toast', 353 + }), 354 + ), 355 + ) 356 + } else if (e instanceof InvalidInteractionSettingsError) { 357 + Toast.show( 358 + _(msg({message: 'Invalid interaction settings.', context: 'toast'})), 359 + ) 360 + } else { 361 + Toast.show( 362 + _( 363 + msg({ 364 + message: 'Updating reply visibility failed', 365 + context: 'toast', 366 + }), 367 + ), 368 + ) 369 + logger.error(`Failed to ${action} reply`, {safeMessage: e.message}) 370 + } 346 371 } 347 372 } 348 373
+34
src/state/queries/threadgate/index.ts
··· 25 25 export * from '#/state/queries/threadgate/types' 26 26 export * from '#/state/queries/threadgate/util' 27 27 28 + /** 29 + * Must match the threadgate lexicon record definition. 30 + */ 31 + export const MAX_HIDDEN_REPLIES = 300 32 + 28 33 export const threadgateRecordQueryKeyRoot = 'threadgate-record' 29 34 export const createThreadgateRecordQueryKey = (uri: string) => [ 30 35 threadgateRecordQueryKeyRoot, ··· 205 210 }) 206 211 const next = await callback(prev) 207 212 if (!next) return 213 + validateThreadgateRecordOrThrow(next) 208 214 await writeThreadgateRecord({ 209 215 agent, 210 216 postUri, ··· 358 364 }, 359 365 }) 360 366 } 367 + 368 + export class MaxHiddenRepliesError extends Error { 369 + constructor(message?: string) { 370 + super(message || 'Maximum number of hidden replies reached') 371 + this.name = 'MaxHiddenRepliesError' 372 + } 373 + } 374 + 375 + export class InvalidInteractionSettingsError extends Error { 376 + constructor(message?: string) { 377 + super(message || 'Invalid interaction settings') 378 + this.name = 'InvalidInteractionSettingsError' 379 + } 380 + } 381 + 382 + export function validateThreadgateRecordOrThrow( 383 + record: AppBskyFeedThreadgate.Record, 384 + ) { 385 + const result = AppBskyFeedThreadgate.validateRecord(record) 386 + 387 + if (result.success) { 388 + if ((result.value.hiddenReplies?.length ?? 0) > MAX_HIDDEN_REPLIES) { 389 + throw new MaxHiddenRepliesError() 390 + } 391 + } else { 392 + throw new InvalidInteractionSettingsError() 393 + } 394 + }