Labeling & moderation updates [DRAFT] (#1057)
* First pass moving to the new labeling sdk (it compiles) * Correct behaviors around interpreting label moderation * Improve moderation state rendering * Improve hiders and alerts * Improve handling of mutes * Improve profile warnings * Add profile blurring to profile header * Add blocks to test cases * Render labels on profile cards, do not filter * Filter profiles from suggestions using moderation * Apply profile blurring to ProfileCard * Handle blocked and deleted quote posts * Temporarily translate content filtering settings to new labels * Fix types * Tune ContentHider & PostHider click targets * Put a warning on profilecard label pills * Fix screenhider learnmore link on mobile * Enforce no-override on user avatar * Dont enumerate profile blur-media labels in alerts * Fixes to muted posts (esp quotes of muted users) * Fixes to account/profile warnings * Bump @atproto/api@0.5.0 * Bump @atproto/api@0.5.1 * Fix tests * 1.43 * Remove log * Bump @atproto/api@0.5.2
This commit is contained in:
parent
3ae5a6b631
commit
b154d3ea21
43 changed files with 1193 additions and 717 deletions
|
|
@ -8,6 +8,8 @@ import {
|
|||
AppBskyFeedLike,
|
||||
AppBskyGraphFollow,
|
||||
ComAtprotoLabelDefs,
|
||||
moderatePost,
|
||||
moderateProfile,
|
||||
} from '@atproto/api'
|
||||
import AwaitLock from 'await-lock'
|
||||
import chunk from 'lodash.chunk'
|
||||
|
|
@ -15,16 +17,6 @@ import {bundleAsync} from 'lib/async/bundle'
|
|||
import {RootStoreModel} from '../root-store'
|
||||
import {PostThreadModel} from '../content/post-thread'
|
||||
import {cleanError} from 'lib/strings/errors'
|
||||
import {
|
||||
PostLabelInfo,
|
||||
PostModeration,
|
||||
ModerationBehaviorCode,
|
||||
} from 'lib/labeling/types'
|
||||
import {
|
||||
getPostModeration,
|
||||
filterAccountLabels,
|
||||
filterProfileLabels,
|
||||
} from 'lib/labeling/helpers'
|
||||
|
||||
const GROUPABLE_REASONS = ['like', 'repost', 'follow']
|
||||
const PAGE_SIZE = 30
|
||||
|
|
@ -100,27 +92,19 @@ export class NotificationsFeedItemModel {
|
|||
}
|
||||
}
|
||||
|
||||
get labelInfo(): PostLabelInfo {
|
||||
const addedInfo = this.additionalPost?.thread?.labelInfo
|
||||
return {
|
||||
postLabels: (this.labels || []).concat(addedInfo?.postLabels || []),
|
||||
accountLabels: filterAccountLabels(this.author.labels).concat(
|
||||
addedInfo?.accountLabels || [],
|
||||
),
|
||||
profileLabels: filterProfileLabels(this.author.labels).concat(
|
||||
addedInfo?.profileLabels || [],
|
||||
),
|
||||
isMuted: this.author.viewer?.muted || addedInfo?.isMuted || false,
|
||||
mutedByList: this.author.viewer?.mutedByList || addedInfo?.mutedByList,
|
||||
isBlocking:
|
||||
!!this.author.viewer?.blocking || addedInfo?.isBlocking || false,
|
||||
isBlockedBy:
|
||||
!!this.author.viewer?.blockedBy || addedInfo?.isBlockedBy || false,
|
||||
get shouldFilter(): boolean {
|
||||
if (this.additionalPost?.thread) {
|
||||
const postMod = moderatePost(
|
||||
this.additionalPost.thread.data.post,
|
||||
this.rootStore.preferences.moderationOpts,
|
||||
)
|
||||
return postMod.content.filter || false
|
||||
}
|
||||
}
|
||||
|
||||
get moderation(): PostModeration {
|
||||
return getPostModeration(this.rootStore, this.labelInfo)
|
||||
const profileMod = moderateProfile(
|
||||
this.author,
|
||||
this.rootStore.preferences.moderationOpts,
|
||||
)
|
||||
return profileMod.account.filter || false
|
||||
}
|
||||
|
||||
get numUnreadInGroup(): number {
|
||||
|
|
@ -565,8 +549,7 @@ export class NotificationsFeedModel {
|
|||
): NotificationsFeedItemModel[] {
|
||||
return items
|
||||
.filter(item => {
|
||||
const hideByLabel =
|
||||
item.moderation.list.behavior === ModerationBehaviorCode.Hide
|
||||
const hideByLabel = item.shouldFilter
|
||||
let mutedThread = !!(
|
||||
item.reasonSubjectRootUri &&
|
||||
this.rootStore.mutedThreads.uris.has(item.reasonSubjectRootUri)
|
||||
|
|
|
|||
|
|
@ -3,21 +3,13 @@ import {
|
|||
AppBskyFeedPost as FeedPost,
|
||||
AppBskyFeedDefs,
|
||||
RichText,
|
||||
moderatePost,
|
||||
PostModeration,
|
||||
} from '@atproto/api'
|
||||
import {RootStoreModel} from '../root-store'
|
||||
import {updateDataOptimistically} from 'lib/async/revertible'
|
||||
import {PostLabelInfo, PostModeration} from 'lib/labeling/types'
|
||||
import {
|
||||
getEmbedLabels,
|
||||
getEmbedMuted,
|
||||
getEmbedMutedByList,
|
||||
getEmbedBlocking,
|
||||
getEmbedBlockedBy,
|
||||
filterAccountLabels,
|
||||
filterProfileLabels,
|
||||
getPostModeration,
|
||||
} from 'lib/labeling/helpers'
|
||||
import {track} from 'lib/analytics/analytics'
|
||||
import {hackAddDeletedEmbed} from 'lib/api/hack-add-deleted-embed'
|
||||
|
||||
type FeedViewPost = AppBskyFeedDefs.FeedViewPost
|
||||
type ReasonRepost = AppBskyFeedDefs.ReasonRepost
|
||||
|
|
@ -44,6 +36,7 @@ export class PostsFeedItemModel {
|
|||
if (FeedPost.isRecord(this.post.record)) {
|
||||
const valid = FeedPost.validateRecord(this.post.record)
|
||||
if (valid.success) {
|
||||
hackAddDeletedEmbed(this.post)
|
||||
this.postRecord = this.post.record
|
||||
this.richText = new RichText(this.postRecord, {cleanNewlines: true})
|
||||
} else {
|
||||
|
|
@ -86,33 +79,8 @@ export class PostsFeedItemModel {
|
|||
return this.rootStore.mutedThreads.uris.has(this.rootUri)
|
||||
}
|
||||
|
||||
get labelInfo(): PostLabelInfo {
|
||||
return {
|
||||
postLabels: (this.post.labels || []).concat(
|
||||
getEmbedLabels(this.post.embed),
|
||||
),
|
||||
accountLabels: filterAccountLabels(this.post.author.labels),
|
||||
profileLabels: filterProfileLabels(this.post.author.labels),
|
||||
isMuted:
|
||||
this.post.author.viewer?.muted ||
|
||||
getEmbedMuted(this.post.embed) ||
|
||||
false,
|
||||
mutedByList:
|
||||
this.post.author.viewer?.mutedByList ||
|
||||
getEmbedMutedByList(this.post.embed),
|
||||
isBlocking:
|
||||
!!this.post.author.viewer?.blocking ||
|
||||
getEmbedBlocking(this.post.embed) ||
|
||||
false,
|
||||
isBlockedBy:
|
||||
!!this.post.author.viewer?.blockedBy ||
|
||||
getEmbedBlockedBy(this.post.embed) ||
|
||||
false,
|
||||
}
|
||||
}
|
||||
|
||||
get moderation(): PostModeration {
|
||||
return getPostModeration(this.rootStore, this.labelInfo)
|
||||
return moderatePost(this.post, this.rootStore.preferences.moderationOpts)
|
||||
}
|
||||
|
||||
copy(v: FeedViewPost) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import {makeAutoObservable} from 'mobx'
|
||||
import {RootStoreModel} from '../root-store'
|
||||
import {FeedViewPostsSlice} from 'lib/api/feed-manip'
|
||||
import {mergePostModerations} from 'lib/labeling/helpers'
|
||||
import {PostsFeedItemModel} from './post'
|
||||
|
||||
let _idCounter = 0
|
||||
|
|
@ -55,7 +54,20 @@ export class PostsFeedSliceModel {
|
|||
}
|
||||
|
||||
get moderation() {
|
||||
return mergePostModerations(this.items.map(item => item.moderation))
|
||||
// prefer the most stringent item
|
||||
const topItem = this.items.find(item => item.moderation.content.filter)
|
||||
if (topItem) {
|
||||
return topItem.moderation
|
||||
}
|
||||
// otherwise just use the first one
|
||||
return this.items[0].moderation
|
||||
}
|
||||
|
||||
shouldFilter(ignoreFilterForDid: string | undefined): boolean {
|
||||
const mods = this.items
|
||||
.filter(item => item.post.author.did !== ignoreFilterForDid)
|
||||
.map(item => item.moderation)
|
||||
return !!mods.find(mod => mod.content.filter)
|
||||
}
|
||||
|
||||
containsUri(uri: string) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue