Add validation to threadgate records, check for max hidden replies (#9178)
This commit is contained in:
@@ -46,7 +46,12 @@ import {
|
|||||||
useProfileBlockMutationQueue,
|
useProfileBlockMutationQueue,
|
||||||
useProfileMuteMutationQueue,
|
useProfileMuteMutationQueue,
|
||||||
} from '#/state/queries/profile'
|
} from '#/state/queries/profile'
|
||||||
import {useToggleReplyVisibilityMutation} from '#/state/queries/threadgate'
|
import {
|
||||||
|
InvalidInteractionSettingsError,
|
||||||
|
MAX_HIDDEN_REPLIES,
|
||||||
|
MaxHiddenRepliesError,
|
||||||
|
useToggleReplyVisibilityMutation,
|
||||||
|
} from '#/state/queries/threadgate'
|
||||||
import {useRequireAuth, useSession} from '#/state/session'
|
import {useRequireAuth, useSession} from '#/state/session'
|
||||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
@@ -339,10 +344,30 @@ let PostMenuItems = ({
|
|||||||
: _(msg({message: 'Reply visibility updated', context: 'toast'})),
|
: _(msg({message: 'Reply visibility updated', context: 'toast'})),
|
||||||
)
|
)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
Toast.show(
|
if (e instanceof MaxHiddenRepliesError) {
|
||||||
_(msg({message: 'Updating reply visibility failed', context: 'toast'})),
|
Toast.show(
|
||||||
)
|
_(
|
||||||
logger.error(`Failed to ${action} reply`, {safeMessage: e.message})
|
msg({
|
||||||
|
message: `You can hide a maximum of ${MAX_HIDDEN_REPLIES} replies.`,
|
||||||
|
context: 'toast',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else if (e instanceof InvalidInteractionSettingsError) {
|
||||||
|
Toast.show(
|
||||||
|
_(msg({message: 'Invalid interaction settings.', context: 'toast'})),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Toast.show(
|
||||||
|
_(
|
||||||
|
msg({
|
||||||
|
message: 'Updating reply visibility failed',
|
||||||
|
context: 'toast',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
logger.error(`Failed to ${action} reply`, {safeMessage: e.message})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ import * as bsky from '#/types/bsky'
|
|||||||
export * from '#/state/queries/threadgate/types'
|
export * from '#/state/queries/threadgate/types'
|
||||||
export * from '#/state/queries/threadgate/util'
|
export * from '#/state/queries/threadgate/util'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must match the threadgate lexicon record definition.
|
||||||
|
*/
|
||||||
|
export const MAX_HIDDEN_REPLIES = 300
|
||||||
|
|
||||||
export const threadgateRecordQueryKeyRoot = 'threadgate-record'
|
export const threadgateRecordQueryKeyRoot = 'threadgate-record'
|
||||||
export const createThreadgateRecordQueryKey = (uri: string) => [
|
export const createThreadgateRecordQueryKey = (uri: string) => [
|
||||||
threadgateRecordQueryKeyRoot,
|
threadgateRecordQueryKeyRoot,
|
||||||
@@ -205,6 +210,7 @@ export async function upsertThreadgate(
|
|||||||
})
|
})
|
||||||
const next = await callback(prev)
|
const next = await callback(prev)
|
||||||
if (!next) return
|
if (!next) return
|
||||||
|
validateThreadgateRecordOrThrow(next)
|
||||||
await writeThreadgateRecord({
|
await writeThreadgateRecord({
|
||||||
agent,
|
agent,
|
||||||
postUri,
|
postUri,
|
||||||
@@ -358,3 +364,31 @@ export function useToggleReplyVisibilityMutation() {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MaxHiddenRepliesError extends Error {
|
||||||
|
constructor(message?: string) {
|
||||||
|
super(message || 'Maximum number of hidden replies reached')
|
||||||
|
this.name = 'MaxHiddenRepliesError'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class InvalidInteractionSettingsError extends Error {
|
||||||
|
constructor(message?: string) {
|
||||||
|
super(message || 'Invalid interaction settings')
|
||||||
|
this.name = 'InvalidInteractionSettingsError'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function validateThreadgateRecordOrThrow(
|
||||||
|
record: AppBskyFeedThreadgate.Record,
|
||||||
|
) {
|
||||||
|
const result = AppBskyFeedThreadgate.validateRecord(record)
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
if ((result.value.hiddenReplies?.length ?? 0) > MAX_HIDDEN_REPLIES) {
|
||||||
|
throw new MaxHiddenRepliesError()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new InvalidInteractionSettingsError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user