mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at thread-bug 151 lines 3.7 kB view raw
1import React from 'react' 2import { 3 type AppBskyLabelerDefs, 4 BskyAgent, 5 type ComAtprotoLabelDefs, 6 type InterpretedLabelValueDefinition, 7 LABELS, 8 type ModerationCause, 9 type ModerationOpts, 10 type ModerationUI, 11} from '@atproto/api' 12 13import {sanitizeDisplayName} from '#/lib/strings/display-names' 14import {sanitizeHandle} from '#/lib/strings/handles' 15import {type AppModerationCause} from '#/components/Pills' 16 17export const ADULT_CONTENT_LABELS = ['sexual', 'nudity', 'porn'] 18export const OTHER_SELF_LABELS = ['graphic-media'] 19export const SELF_LABELS = [...ADULT_CONTENT_LABELS, ...OTHER_SELF_LABELS] 20 21export type AdultSelfLabel = (typeof ADULT_CONTENT_LABELS)[number] 22export type OtherSelfLabel = (typeof OTHER_SELF_LABELS)[number] 23export type SelfLabel = (typeof SELF_LABELS)[number] 24 25export function getModerationCauseKey( 26 cause: ModerationCause | AppModerationCause, 27): string { 28 const source = 29 cause.source.type === 'labeler' 30 ? cause.source.did 31 : cause.source.type === 'list' 32 ? cause.source.list.uri 33 : 'user' 34 if (cause.type === 'label') { 35 return `label:${cause.label.val}:${source}` 36 } 37 return `${cause.type}:${source}` 38} 39 40export function isJustAMute(modui: ModerationUI): boolean { 41 return modui.filters.length === 1 && modui.filters[0].type === 'muted' 42} 43 44export function moduiContainsHideableOffense(modui: ModerationUI): boolean { 45 const label = modui.filters.at(0) 46 if (label && label.type === 'label') { 47 return labelIsHideableOffense(label.label) 48 } 49 return false 50} 51 52export function labelIsHideableOffense( 53 label: ComAtprotoLabelDefs.Label, 54): boolean { 55 return ['!hide', '!takedown'].includes(label.val) 56} 57 58export function getLabelingServiceTitle({ 59 displayName, 60 handle, 61}: { 62 displayName?: string 63 handle: string 64}) { 65 return displayName 66 ? sanitizeDisplayName(displayName) 67 : sanitizeHandle(handle, '@') 68} 69 70export function lookupLabelValueDefinition( 71 labelValue: string, 72 customDefs: InterpretedLabelValueDefinition[] | undefined, 73): InterpretedLabelValueDefinition | undefined { 74 let def 75 if (!labelValue.startsWith('!') && customDefs) { 76 def = customDefs.find(d => d.identifier === labelValue) 77 } 78 if (!def) { 79 def = LABELS[labelValue as keyof typeof LABELS] 80 } 81 return def 82} 83 84export function isAppLabeler( 85 labeler: 86 | string 87 | AppBskyLabelerDefs.LabelerView 88 | AppBskyLabelerDefs.LabelerViewDetailed, 89): boolean { 90 if (typeof labeler === 'string') { 91 return BskyAgent.appLabelers.includes(labeler) 92 } 93 return BskyAgent.appLabelers.includes(labeler.creator.did) 94} 95 96export function isLabelerSubscribed( 97 labeler: 98 | string 99 | AppBskyLabelerDefs.LabelerView 100 | AppBskyLabelerDefs.LabelerViewDetailed, 101 modOpts: ModerationOpts, 102) { 103 labeler = typeof labeler === 'string' ? labeler : labeler.creator.did 104 if (isAppLabeler(labeler)) { 105 return true 106 } 107 return modOpts.prefs.labelers.find(l => l.did === labeler) 108} 109 110export type Subject = 111 | { 112 uri: string 113 cid: string 114 } 115 | { 116 did: string 117 } 118 119export function useLabelSubject({label}: {label: ComAtprotoLabelDefs.Label}): { 120 subject: Subject 121} { 122 return React.useMemo(() => { 123 const {cid, uri} = label 124 if (cid) { 125 return { 126 subject: { 127 uri, 128 cid, 129 }, 130 } 131 } else { 132 return { 133 subject: { 134 did: uri, 135 }, 136 } 137 } 138 }, [label]) 139} 140 141export function unique( 142 value: ModerationCause, 143 index: number, 144 array: ModerationCause[], 145) { 146 return ( 147 array.findIndex( 148 item => getModerationCauseKey(item) === getModerationCauseKey(value), 149 ) === index 150 ) 151}