[docx] final commit @ Tue 23 Jan 19:23:08 EET 2024 for file 6906

Signed-off-by: Ari Archer <ari.web.xyz@gmail.com>
This commit is contained in:
Ari Archer 2024-01-23 19:23:08 +02:00
parent e90b21ec83
commit c53a0a714d
No known key found for this signature in database
GPG Key ID: A50D5B4B599AF8A2
212 changed files with 0 additions and 19267 deletions

View File

@ -1,181 +0,0 @@
package com.twitter.visibility.interfaces.notifications
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.notificationservice.model.notification.Notification
import com.twitter.notificationservice.model.notification.NotificationType
import com.twitter.notificationservice.model.notification.SimpleActivityNotification
import com.twitter.servo.util.Gate
import com.twitter.stitch.Stitch
import com.twitter.visibility.VisibilityLibrary
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.builder.tweets.CommunityNotificationFeatures
import com.twitter.visibility.builder.tweets.UnmentionNotificationFeatures
import com.twitter.visibility.builder.users.AuthorDeviceFeatures
import com.twitter.visibility.builder.users.AuthorFeatures
import com.twitter.visibility.builder.users.RelationshipFeatures
import com.twitter.visibility.builder.users.ViewerAdvancedFilteringFeatures
import com.twitter.visibility.builder.users.ViewerFeatures
import com.twitter.visibility.common.TweetSource
import com.twitter.visibility.common.UserDeviceSource
import com.twitter.visibility.common.UserRelationshipSource
import com.twitter.visibility.common.UserSource
import com.twitter.visibility.features.AuthorUserLabels
import com.twitter.visibility.features.FeatureMap
import com.twitter.visibility.models.ContentId.NotificationId
import com.twitter.visibility.models.SafetyLevel.NotificationsWriterV2
import com.twitter.visibility.models.ViewerContext
import com.twitter.visibility.rules.State.FeatureFailed
import com.twitter.visibility.rules.State.MissingFeature
import com.twitter.visibility.rules.Action
import com.twitter.visibility.rules.RuleResult
import com.twitter.visibility.rules.{Allow => AllowAction}
object NotificationsVisibilityLibrary {
type Type = Notification => Stitch[NotificationsFilteringResponse]
private val AllowResponse: Stitch[NotificationsFilteringResponse] = Stitch.value(Allow)
def isApplicableOrganicNotificationType(notificationType: NotificationType): Boolean = {
NotificationType.isTlsActivityType(notificationType) ||
NotificationType.isReactionType(notificationType)
}
def apply(
visibilityLibrary: VisibilityLibrary,
userSource: UserSource,
userRelationshipSource: UserRelationshipSource,
userDeviceSource: UserDeviceSource,
tweetSource: TweetSource,
enableShimFeatureHydration: Gate[Unit] = Gate.False,
enableCommunityTweetHydration: Gate[Long] = Gate.False,
enableUnmentionHydration: Gate[Long] = Gate.False,
): Type = {
val libraryStatsReceiver = visibilityLibrary.statsReceiver
lazy val vfEngineCounter = libraryStatsReceiver.counter("vf_engine_requests")
val authorFeatures = new AuthorFeatures(userSource, libraryStatsReceiver)
val authorDeviceFeatures = new AuthorDeviceFeatures(userDeviceSource, libraryStatsReceiver)
val viewerFeatures = new ViewerFeatures(userSource, libraryStatsReceiver)
val communityNotificationFeatures =
new CommunityNotificationFeatures(
tweetSource,
enableCommunityTweetHydration,
libraryStatsReceiver)
val unmentionNotificationFeatures = new UnmentionNotificationFeatures(
tweetSource = tweetSource,
enableUnmentionHydration = enableUnmentionHydration,
statsReceiver = libraryStatsReceiver
)
val viewerAdvancedFilteringFeatures =
new ViewerAdvancedFilteringFeatures(userSource, libraryStatsReceiver)
val relationshipFeatures =
new RelationshipFeatures(userRelationshipSource, libraryStatsReceiver)
val isShimFeatureHydrationEnabled = enableShimFeatureHydration()
def runRuleEngine(
visibilityLibrary: VisibilityLibrary,
candidate: Notification
): Stitch[VisibilityResult] = {
candidate match {
case notification: SimpleActivityNotification[_] =>
vfEngineCounter.incr()
val featureMap = visibilityLibrary.featureMapBuilder(
Seq(
viewerFeatures.forViewerId(Some(notification.target)),
viewerAdvancedFilteringFeatures.forViewerId(Some(notification.target)),
authorFeatures.forAuthorId(notification.subjectId),
authorDeviceFeatures.forAuthorId(notification.subjectId),
relationshipFeatures
.forAuthorId(notification.subjectId, Some(notification.target)),
communityNotificationFeatures.forNotification(notification),
unmentionNotificationFeatures.forNotification(notification)
)
)
if (isShimFeatureHydrationEnabled) {
FeatureMap.resolve(featureMap, libraryStatsReceiver).flatMap { resolvedFeatureMap =>
visibilityLibrary.runRuleEngine(
contentId =
featureMap = resolvedFeatureMap,
viewerContext =
ViewerContext.fromContextWithViewerIdFallback(Some(notification.target)),
safetyLevel = NotificationsWriterV2
)
}
} else {
visibilityLibrary.runRuleEngine(
contentId = NotificationId(tweetId = None),
featureMap = featureMap,
viewerContext =
ViewerContext.fromContextWithViewerIdFallback(Some(notification.target)),
safetyLevel = NotificationsWriterV2
)
}
}
}
{
case candidate if isApplicableOrganicNotificationType(candidate.notificationType) =>
runRuleEngine(visibilityLibrary, candidate)
.flatMap(failCloseForFailures(_, libraryStatsReceiver))
case _ =>
AllowResponse
}
}
def failCloseForFailures(
visibilityResult: VisibilityResult,
stats: StatsReceiver
): Stitch[NotificationsFilteringResponse] = {
lazy val vfEngineSuccess = stats.counter("vf_engine_success")
lazy val vfEngineFailures = stats.counter("vf_engine_failures")
lazy val vfEngineFailuresMissing = stats.scope("vf_engine_failures").counter("missing")
lazy val vfEngineFailuresFailed = stats.scope("vf_engine_failures").counter("failed")
lazy val vfEngineFiltered = stats.counter("vf_engine_filtered")
val isFailedOrMissingFeature: RuleResult => Boolean = {
case RuleResult(_, FeatureFailed(features)) =>
!(features.contains(AuthorUserLabels) && features.size == 1)
case RuleResult(_, MissingFeature(_)) => true
case _ => false
}
val failedRuleResults =
visibilityResult.ruleResultMap.values.filter(isFailedOrMissingFeature(_))
val (failedFeatures, missingFeatures) = failedRuleResults.partition {
case RuleResult(_, FeatureFailed(_)) => true
case RuleResult(_, MissingFeature(_)) => false
case _ => false
}
val failedOrMissingFeatures = failedRuleResults
.collect {
case RuleResult(_, FeatureFailed(features)) => features.keySet
case RuleResult(_, MissingFeature(features)) => features
}.toSet.flatten
visibilityResult.verdict match {
case AllowAction if failedOrMissingFeatures.isEmpty =>
vfEngineSuccess.incr()
AllowResponse
case AllowAction if failedOrMissingFeatures.nonEmpty =>
vfEngineFailures.incr()
if (missingFeatures.nonEmpty) {
vfEngineFailuresMissing.incr()
}
if (failedFeatures.nonEmpty) {
vfEngineFailuresFailed.incr()
}
Stitch.value(Failed(failedOrMissingFeatures))
case action: Action =>
vfEngineFiltered.incr()
Stitch.value(Filtered(action))
}
}
}

View File

@ -1,31 +0,0 @@
scala_library(
sources = ["*.scala"],
compiler_option_sets = ["fatal_warnings"],
strict_deps = True,
tags = ["bazel-compatible"],
dependencies = [
"3rdparty/jvm/com/twitter/storehaus:core",
"src/thrift/com/twitter/spam/rtf:tweet-rtf-event-scala",
"src/thrift/com/twitter/tweetypie:events-scala",
"src/thrift/com/twitter/tweetypie:tweet-scala",
"stitch/stitch-core",
"stitch/stitch-tweetypie/src/main/scala",
"strato/src/main/scala/com/twitter/strato/catalog",
"strato/src/main/scala/com/twitter/strato/client",
"visibility/common/src/main/scala/com/twitter/visibility/common",
"visibility/common/src/main/scala/com/twitter/visibility/common/stitch",
"visibility/common/src/main/thrift/com/twitter/visibility:action-scala",
"visibility/lib/src/main/resources/config",
"visibility/lib/src/main/scala/com/twitter/visibility",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/media",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/tweets",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/users",
"visibility/lib/src/main/scala/com/twitter/visibility/configapi/params",
"visibility/lib/src/main/scala/com/twitter/visibility/features",
"visibility/lib/src/main/scala/com/twitter/visibility/interfaces/common/tweets",
],
exports = [
"visibility/common/src/main/scala/com/twitter/visibility/common",
"visibility/lib/src/main/scala/com/twitter/visibility",
],
)

View File

@ -1,21 +0,0 @@
package com.twitter.visibility.interfaces.push_service
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.spam.rtf.thriftscala.SafetyLabelMap
import com.twitter.stitch.Stitch
import com.twitter.strato.client.{Client => StratoClient}
import com.twitter.strato.thrift.ScroogeConvImplicits._
import com.twitter.visibility.common.stitch.StitchHelpers
object PushServiceSafetyLabelMapFetcher {
val Column = "frigate/magicrecs/tweetSafetyLabels"
def apply(
client: StratoClient,
statsReceiver: StatsReceiver
): Long => Stitch[Option[SafetyLabelMap]] = {
val stats = statsReceiver.scope("strato_tweet_safety_labels")
lazy val fetcher = client.fetcher[Long, SafetyLabelMap](Column)
tweetId => StitchHelpers.observe(stats)(fetcher.fetch(tweetId).map(_.v))
}
}

View File

@ -1,179 +0,0 @@
package com.twitter.visibility.interfaces.push_service
import com.twitter.gizmoduck.thriftscala.User
import com.twitter.servo.util.Gate
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.stitch.Stitch
import com.twitter.stitch.tweetypie.TweetyPie.TweetyPieResult
import com.twitter.storehaus.ReadableStore
import com.twitter.strato.client.{Client => StratoClient}
import com.twitter.tweetypie.thriftscala.Tweet
import com.twitter.visibility.VisibilityLibrary
import com.twitter.visibility.builder.tweets.TweetFeatures
import com.twitter.visibility.builder.tweets.StratoTweetLabelMaps
import com.twitter.visibility.builder.users.AuthorFeatures
import com.twitter.visibility.builder.users.RelationshipFeatures
import com.twitter.visibility.builder.users.ViewerFeatures
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.common._
import com.twitter.visibility.common.UserRelationshipSource
import com.twitter.visibility.common.UserSource
import com.twitter.visibility.features.FeatureMap
import com.twitter.visibility.features.TweetIsInnerQuotedTweet
import com.twitter.visibility.features.TweetIsRetweet
import com.twitter.visibility.features.TweetIsSourceTweet
import com.twitter.visibility.interfaces.push_service.PushServiceVisibilityLibraryUtil._
import com.twitter.visibility.models.ContentId
import com.twitter.visibility.models.ViewerContext
object TweetType extends Enumeration {
type TweetType = Value
val ORIGINAL, SOURCE, QUOTED = Value
}
import com.twitter.visibility.interfaces.push_service.TweetType._
object PushServiceVisibilityLibrary {
type Type = PushServiceVisibilityRequest => Stitch[PushServiceVisibilityResponse]
def apply(
visibilityLibrary: VisibilityLibrary,
userSource: UserSource,
userRelationshipSource: UserRelationshipSource,
stratoClient: StratoClient,
enableParityTest: Gate[Unit] = Gate.False,
cachedTweetyPieStoreV2: ReadableStore[Long, TweetyPieResult] = ReadableStore.empty,
safeCachedTweetyPieStoreV2: ReadableStore[Long, TweetyPieResult] = ReadableStore.empty,
)(
implicit statsReceiver: StatsReceiver
): Type = {
val stats = statsReceiver.scope("push_service_vf")
val candidateTweetCounter = stats.counter("request_cnt")
val allowedTweetCounter = stats.counter("allow_cnt")
val droppedTweetCounter = stats.counter("drop_cnt")
val failedTweetCounter = stats.counter("fail_cnt")
val authorLabelsEmptyCount = stats.counter("author_labels_empty_cnt")
val authorLabelsCount = stats.counter("author_labels_cnt")
val tweetLabelMaps = new StratoTweetLabelMaps(
SafetyLabelMapSource.fromSafetyLabelMapFetcher(
PushServiceSafetyLabelMapFetcher(stratoClient, stats)))
val viewerFeatures = new ViewerFeatures(UserSource.empty, stats)
val tweetFeatures = new TweetFeatures(tweetLabelMaps, stats)
val authorFeatures = new AuthorFeatures(userSource, stats)
val relationshipFeatures = new RelationshipFeatures(UserRelationshipSource.empty, stats)
val parityTester = new PushServiceVisibilityLibraryParity(
cachedTweetyPieStoreV2,
safeCachedTweetyPieStoreV2
)(statsReceiver)
def buildFeatureMap(
request: PushServiceVisibilityRequest,
tweet: Tweet,
tweetType: TweetType,
author: Option[User] = None,
): FeatureMap = {
val authorId = author.map(_.id) orElse getAuthorId(tweet)
(author.map(authorFeatures.forAuthor(_)) orElse
getAuthorId(tweet).map(authorFeatures.forAuthorId(_))) match {
case Some(authorVisibilityFeatures) =>
visibilityLibrary.featureMapBuilder(
Seq(
viewerFeatures.forViewerContext(ViewerContext.fromContextWithViewerIdFallback(None)),
tweetFeatures.forTweet(tweet),
authorVisibilityFeatures,
relationshipFeatures.forAuthorId(authorId.get, None),
_.withConstantFeature(TweetIsInnerQuotedTweet, tweetType == QUOTED),
_.withConstantFeature(TweetIsRetweet, request.isRetweet),
_.withConstantFeature(TweetIsSourceTweet, tweetType == SOURCE)
)
)
case _ =>
visibilityLibrary.featureMapBuilder(
Seq(
viewerFeatures.forViewerContext(ViewerContext.fromContextWithViewerIdFallback(None)),
tweetFeatures.forTweet(tweet),
_.withConstantFeature(TweetIsInnerQuotedTweet, tweetType == QUOTED),
_.withConstantFeature(TweetIsRetweet, request.isRetweet),
_.withConstantFeature(TweetIsSourceTweet, tweetType == SOURCE)
)
)
}
}
def runRuleEngineForTweet(
request: PushServiceVisibilityRequest,
tweet: Tweet,
tweetType: TweetType,
author: Option[User] = None,
): Stitch[VisibilityResult] = {
val featureMap = buildFeatureMap(request, tweet, tweetType, author)
val contentId = ContentId.TweetId(tweet.id)
visibilityLibrary.runRuleEngine(
contentId,
featureMap,
request.viewerContext,
request.safetyLevel)
}
def runRuleEngineForAuthor(
request: PushServiceVisibilityRequest,
tweet: Tweet,
tweetType: TweetType,
author: Option[User] = None,
): Stitch[VisibilityResult] = {
val featureMap = buildFeatureMap(request, tweet, tweetType, author)
val authorId = author.map(_.id).getOrElse(getAuthorId(tweet).get)
val contentId = ContentId.UserId(authorId)
visibilityLibrary.runRuleEngine(
contentId,
featureMap,
request.viewerContext,
request.safetyLevel)
}
def getAllVisibilityFilters(
request: PushServiceVisibilityRequest
): Stitch[PushServiceVisibilityResponse] = {
val tweetResult =
runRuleEngineForTweet(request, request.tweet, ORIGINAL, Some(request.author))
val authorResult =
runRuleEngineForAuthor(request, request.tweet, ORIGINAL, Some(request.author))
val sourceTweetResult = request.sourceTweet
.map(runRuleEngineForTweet(request, _, SOURCE).map(Some(_))).getOrElse(Stitch.None)
val quotedTweetResult = request.quotedTweet
.map(runRuleEngineForTweet(request, _, QUOTED).map(Some(_))).getOrElse(Stitch.None)
Stitch.join(tweetResult, authorResult, sourceTweetResult, quotedTweetResult).map {
case (tweetResult, authorResult, sourceTweetResult, quotedTweetResult) =>
PushServiceVisibilityResponse(
tweetResult,
authorResult,
sourceTweetResult,
quotedTweetResult)
}
}
{ request: PushServiceVisibilityRequest =>
candidateTweetCounter.incr()
request.author.labels match {
case Some(labels) if (!labels._1.isEmpty) => authorLabelsCount.incr()
case _ => authorLabelsEmptyCount.incr()
}
val response = getAllVisibilityFilters(request)
.onSuccess { response =>
if (response.shouldAllow) allowedTweetCounter.incr() else droppedTweetCounter.incr()
}.onFailure { _ => failedTweetCounter.incr() }
if (enableParityTest()) {
response.applyEffect { resp => Stitch.async(parityTester.runParityTest(request, resp)) }
} else {
response
}
}
}
}

View File

@ -1,74 +0,0 @@
package com.twitter.visibility.interfaces.push_service
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.stitch.Stitch
import com.twitter.stitch.tweetypie.TweetyPie.TweetyPieResult
import com.twitter.storehaus.ReadableStore
import com.twitter.logging.Logger
import com.twitter.visibility.models.SafetyLevel
class PushServiceVisibilityLibraryParity(
magicRecsV2tweetyPieStore: ReadableStore[Long, TweetyPieResult],
magicRecsAggressiveV2tweetyPieStore: ReadableStore[Long, TweetyPieResult]
)(
implicit statsReceiver: StatsReceiver) {
private val stats = statsReceiver.scope("push_service_vf_parity")
private val requests = stats.counter("requests")
private val equal = stats.counter("equal")
private val notEqual = stats.counter("notEqual")
private val failures = stats.counter("failures")
private val bothAllow = stats.counter("bothAllow")
private val bothReject = stats.counter("bothReject")
private val onlyTweetypieRejects = stats.counter("onlyTweetypieRejects")
private val onlyPushServiceRejects = stats.counter("onlyPushServiceRejects")
val log = Logger.get("pushservice_vf_parity")
def runParityTest(
req: PushServiceVisibilityRequest,
resp: PushServiceVisibilityResponse
): Stitch[Unit] = {
requests.incr()
getTweetypieResult(req).map { tweetypieResult =>
val isSameVerdict = (tweetypieResult == resp.shouldAllow)
isSameVerdict match {
case true => equal.incr()
case false => notEqual.incr()
}
(tweetypieResult, resp.shouldAllow) match {
case (true, true) => bothAllow.incr()
case (true, false) => onlyPushServiceRejects.incr()
case (false, true) => onlyTweetypieRejects.incr()
case (false, false) => bothReject.incr()
}
resp.getDropRules.foreach { dropRule =>
stats.counter(s"rules/${dropRule.name}/requests").incr()
stats
.counter(
s"rules/${dropRule.name}/" ++ (if (isSameVerdict) "equal" else "notEqual")).incr()
}
if (!isSameVerdict) {
val dropRuleNames = resp.getDropRules.map("<<" ++ _.name ++ ">>").mkString(",")
val safetyLevelStr = req.safetyLevel match {
case SafetyLevel.MagicRecsAggressiveV2 => "aggr"
case _ => " "
}
log.info(
s"ttweetId:${req.tweet.id} () push:${resp.shouldAllow}, tweety:${tweetypieResult}, rules=[${dropRuleNames}] lvl=${safetyLevelStr}")
}
}
}
def getTweetypieResult(request: PushServiceVisibilityRequest): Stitch[Boolean] = {
val tweetypieStore = request.safetyLevel match {
case SafetyLevel.MagicRecsAggressiveV2 => magicRecsAggressiveV2tweetyPieStore
case _ => magicRecsV2tweetyPieStore
}
Stitch.callFuture(
tweetypieStore.get(request.tweet.id).onFailure(_ => failures.incr()).map(x => x.isDefined))
}
}

View File

@ -1,57 +0,0 @@
package com.twitter.visibility.interfaces.push_service
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.tweetypie.thriftscala.Tweet
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.rules.Rule
import com.twitter.visibility.rules.RuleResult
import com.twitter.visibility.rules.State
object PushServiceVisibilityLibraryUtil {
def ruleEnabled(ruleResult: RuleResult): Boolean = {
ruleResult.state match {
case State.Disabled => false
case State.ShortCircuited => false
case _ => true
}
}
def getMissingFeatures(ruleResult: RuleResult): Set[String] = {
ruleResult.state match {
case State.MissingFeature(features) => features.map(f => f.name)
case _ => Set.empty
}
}
def getMissingFeatureCounts(results: Seq[VisibilityResult]): Map[String, Int] = {
results
.flatMap(_.ruleResultMap.values.toList)
.flatMap(getMissingFeatures(_).toList).groupBy(identity).mapValues(_.length)
}
def logAllStats(
response: PushServiceVisibilityResponse
)(
implicit statsReceiver: StatsReceiver
) = {
val rulesStatsReceiver = statsReceiver.scope("rules")
logStats(response.tweetVisibilityResult, rulesStatsReceiver.scope("tweet"))
logStats(response.authorVisibilityResult, rulesStatsReceiver.scope("author"))
}
def logStats(result: VisibilityResult, statsReceiver: StatsReceiver) = {
result.ruleResultMap.toList
.filter { case (_, ruleResult) => ruleEnabled(ruleResult) }
.flatMap { case (rule, ruleResult) => getCounters(rule, ruleResult) }
.foreach(statsReceiver.counter(_).incr())
}
def getCounters(rule: Rule, ruleResult: RuleResult): List[String] = {
val missingFeatures = getMissingFeatures(ruleResult)
List(s"${rule.name}/${ruleResult.action.name}") ++
missingFeatures.map(feat => s"${rule.name}/${feat}") ++
missingFeatures
}
def getAuthorId(tweet: Tweet): Option[Long] = tweet.coreData.map(_.userId)
def isRetweet(tweet: Tweet): Boolean = tweet.coreData.flatMap(_.share).isDefined
def isQuotedTweet(tweet: Tweet): Boolean = tweet.quotedTweet.isDefined
}

View File

@ -1,19 +0,0 @@
package com.twitter.visibility.interfaces.push_service
import com.twitter.gizmoduck.thriftscala.User
import com.twitter.tweetypie.thriftscala.Tweet
import com.twitter.visibility.models.SafetyLevel
import com.twitter.visibility.models.ViewerContext
case class PushServiceVisibilityRequest(
tweet: Tweet,
author: User,
viewerContext: ViewerContext,
safetyLevel: SafetyLevel,
sourceTweet: Option[Tweet] = None,
quotedTweet: Option[Tweet] = None,
isRetweet: Boolean = false,
isInnerQuotedTweet: Boolean = false,
isSourceTweet: Boolean = false,
isOutOfNetworkTweet: Boolean = true,
)

View File

@ -1,52 +0,0 @@
package com.twitter.visibility.interfaces.push_service
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.rules.Action
import com.twitter.visibility.rules.Allow
import com.twitter.visibility.rules.Drop
import com.twitter.visibility.rules.Rule
import com.twitter.visibility.rules.RuleResult
case class PushServiceVisibilityResponse(
tweetVisibilityResult: VisibilityResult,
authorVisibilityResult: VisibilityResult,
sourceTweetVisibilityResult: Option[VisibilityResult] = None,
quotedTweetVisibilityResult: Option[VisibilityResult] = None,
) {
def allVisibilityResults: List[VisibilityResult] = {
List(
Some(tweetVisibilityResult),
Some(authorVisibilityResult),
sourceTweetVisibilityResult,
quotedTweetVisibilityResult,
).collect { case Some(result) => result }
}
val shouldAllow: Boolean = !allVisibilityResults.exists(isDrop(_))
def isDrop(response: VisibilityResult): Boolean = response.verdict match {
case _: Drop => true
case Allow => false
case _ => false
}
def isDrop(response: Option[VisibilityResult]): Boolean = response.map(isDrop(_)).getOrElse(false)
def getDropRules(visibilityResult: VisibilityResult): List[Rule] = {
val ruleResultMap = visibilityResult.ruleResultMap
val ruleResults = ruleResultMap.toList
val denyRules = ruleResults.collect { case (rule, RuleResult(Drop(_, _), _)) => rule }
denyRules
}
def getAuthorDropRules: List[Rule] = getDropRules(authorVisibilityResult)
def getTweetDropRules: List[Rule] = getDropRules(tweetVisibilityResult)
def getDropRules: List[Rule] = getAuthorDropRules ++ getTweetDropRules
def getVerdict: Action = {
if (isDrop(authorVisibilityResult)) authorVisibilityResult.verdict
else tweetVisibilityResult.verdict
}
def missingFeatures: Map[String, Int] = PushServiceVisibilityLibraryUtil.getMissingFeatureCounts(
Seq(tweetVisibilityResult, authorVisibilityResult))
}

View File

@ -1,34 +0,0 @@
scala_library(
sources = ["*.scala"],
compiler_option_sets = ["fatal_warnings"],
platform = "java8",
strict_deps = True,
tags = ["bazel-compatible"],
dependencies = [
"3rdparty/jvm/com/twitter/src/java/com/twitter/logpipeline/client:logpipeline-event-publisher-thin",
"decider/src/main/scala",
"mediaservices/media-util/src/main/scala",
"servo/decider/src/main/scala",
"src/thrift/com/twitter/escherbird:media-annotation-structs-scala",
"src/thrift/com/twitter/spam/rtf:safety-level-scala",
"src/thrift/com/twitter/spam/rtf:tweet-rtf-event-scala",
"src/thrift/com/twitter/tweetypie:tweet-scala",
"stitch/stitch-core",
"strato/src/main/scala/com/twitter/strato/client",
"visibility/common/src/main/scala/com/twitter/visibility/common",
"visibility/lib/src/main/resources/config",
"visibility/lib/src/main/scala/com/twitter/visibility",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/media",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/tweets",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/users",
"visibility/lib/src/main/scala/com/twitter/visibility/configapi/configs",
"visibility/lib/src/main/scala/com/twitter/visibility/features",
"visibility/lib/src/main/scala/com/twitter/visibility/interfaces/common/search",
"visibility/lib/src/main/scala/com/twitter/visibility/interfaces/common/tweets",
"visibility/lib/src/main/thrift/com/twitter/visibility/logging:vf-logging-scala",
],
exports = [
"visibility/common/src/main/scala/com/twitter/visibility/common",
"visibility/lib/src/main/scala/com/twitter/visibility",
],
)

View File

@ -1,9 +0,0 @@
package com.twitter.visibility.interfaces.search
import com.twitter.visibility.interfaces.common.search.SearchVFRequestContext
import com.twitter.visibility.models.ViewerContext
case class BatchSearchVisibilityRequest(
tweetContexts: Seq[TweetContext],
viewerContext: ViewerContext,
searchVFRequestContext: SearchVFRequestContext)

View File

@ -1,5 +0,0 @@
package com.twitter.visibility.interfaces.search
case class BatchSearchVisibilityResponse(
visibilityResults: Map[Long, CombinedVisibilityResult],
failedTweetIds: Seq[Long])

View File

@ -1,7 +0,0 @@
package com.twitter.visibility.interfaces.search
import com.twitter.visibility.builder.VisibilityResult
case class CombinedVisibilityResult(
tweetVisibilityResult: VisibilityResult,
quotedTweetVisibilityResult: Option[VisibilityResult])

View File

@ -1,466 +0,0 @@
package com.twitter.visibility.interfaces.search
import com.twitter.decider.Decider
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.mediaservices.media_util.GenericMediaKey
import com.twitter.servo.util.Gate
import com.twitter.stitch.Stitch
import com.twitter.strato.client.{Client => StratoClient}
import com.twitter.tweetypie.thriftscala.Tweet
import com.twitter.util.Return
import com.twitter.util.Stopwatch
import com.twitter.util.Try
import com.twitter.visibility.VisibilityLibrary
import com.twitter.visibility.builder.VerdictLogger
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.builder.media.MediaFeatures
import com.twitter.visibility.builder.media.StratoMediaLabelMaps
import com.twitter.visibility.builder.tweets._
import com.twitter.visibility.builder.users.AuthorFeatures
import com.twitter.visibility.builder.users.RelationshipFeatures
import com.twitter.visibility.builder.users.ViewerFeatures
import com.twitter.visibility.common.MediaSafetyLabelMapSource
import com.twitter.visibility.common.MisinformationPolicySource
import com.twitter.visibility.common.SafetyLabelMapSource
import com.twitter.visibility.common.TrustedFriendsSource
import com.twitter.visibility.common.UserRelationshipSource
import com.twitter.visibility.common.UserSource
import com.twitter.visibility.rules.ComposableActions._
import com.twitter.visibility.configapi.configs.VisibilityDeciderGates
import com.twitter.visibility.features.FeatureMap
import com.twitter.visibility.features.TweetIsInnerQuotedTweet
import com.twitter.visibility.features.TweetIsRetweet
import com.twitter.visibility.features.TweetIsSourceTweet
import com.twitter.visibility.interfaces.common.search.SearchVFRequestContext
import com.twitter.visibility.interfaces.search.SearchVisibilityLibrary.EvaluateTweet
import com.twitter.visibility.interfaces.search.SearchVisibilityLibrary.RequestTweetId
import com.twitter.visibility.interfaces.search.TweetType.EvaluateTweetType
import com.twitter.visibility.logging.thriftscala.VFLibType
import com.twitter.visibility.models.ContentId
import com.twitter.visibility.models.ContentId.BlenderTweetId
import com.twitter.visibility.models.ContentId.TweetId
import com.twitter.visibility.models.SafetyLevel
import com.twitter.visibility.models.SafetyLevel.toThrift
import com.twitter.visibility.models.ViewerContext
import com.twitter.visibility.rules.Action
import com.twitter.visibility.rules.Allow
import com.twitter.visibility.rules.Drop
import com.twitter.visibility.rules.Interstitial
import com.twitter.visibility.rules.TweetInterstitial
object TweetType extends Enumeration {
type EvaluateTweetType = Value
val REQUEST: TweetType.Value = Value(1)
val QUOTED: TweetType.Value = Value(2)
val SOURCE: TweetType.Value = Value(3)
}
import com.twitter.visibility.interfaces.search.TweetType._
object SearchVisibilityLibrary {
type RequestTweetId = Long
type EvaluateTweetId = Long
type EvaluateTweet = Tweet
def buildWithStratoClient(
visibilityLibrary: VisibilityLibrary,
decider: Decider,
stratoClient: StratoClient,
userSource: UserSource,
userRelationshipSource: UserRelationshipSource
): SearchVisibilityLibrary = new SearchVisibilityLibrary(
visibilityLibrary,
decider,
stratoClient,
userSource,
userRelationshipSource,
None
)
def buildWithSafetyLabelMapSource(
visibilityLibrary: VisibilityLibrary,
decider: Decider,
stratoClient: StratoClient,
userSource: UserSource,
userRelationshipSource: UserRelationshipSource,
safetyLabelMapSource: SafetyLabelMapSource
): SearchVisibilityLibrary = new SearchVisibilityLibrary(
visibilityLibrary,
decider,
stratoClient,
userSource,
userRelationshipSource,
Some(safetyLabelMapSource)
)
def createVerdictLogger(
enableVerdictLogger: Gate[Unit],
decider: Decider,
statsReceiver: StatsReceiver
): VerdictLogger = {
if (enableVerdictLogger()) {
VerdictLogger(statsReceiver, decider)
} else {
VerdictLogger.Empty
}
}
def scribeVisibilityVerdict(
result: CombinedVisibilityResult,
enableVerdictScribing: Gate[Unit],
verdictLogger: VerdictLogger,
viewerId: Option[Long],
safetyLevel: SafetyLevel
): Unit = if (enableVerdictScribing()) {
verdictLogger.scribeVerdict(
visibilityResult = result.tweetVisibilityResult,
viewerId = viewerId,
safetyLevel = toThrift(safetyLevel),
vfLibType = VFLibType.SearchVisibilityLibrary)
result.quotedTweetVisibilityResult.map(quotedTweetVisibilityResult =>
verdictLogger.scribeVerdict(
visibilityResult = quotedTweetVisibilityResult,
viewerId = viewerId,
safetyLevel = toThrift(safetyLevel),
vfLibType = VFLibType.SearchVisibilityLibrary))
}
}
class SearchVisibilityLibrary(
visibilityLibrary: VisibilityLibrary,
decider: Decider,
stratoClient: StratoClient,
userSource: UserSource,
userRelationshipSource: UserRelationshipSource,
safetyLabelMapSourceOption: Option[SafetyLabelMapSource]) {
val libraryStatsReceiver = visibilityLibrary.statsReceiver
val stratoClientStatsReceiver = visibilityLibrary.statsReceiver.scope("strato")
val vfEngineCounter = libraryStatsReceiver.counter("vf_engine_requests")
val svlRequestCounter = libraryStatsReceiver.counter("svl_requests")
val vfLatencyOverallStat = libraryStatsReceiver.stat("vf_latency_overall")
val vfLatencyStitchBuildStat = libraryStatsReceiver.stat("vf_latency_stitch_build")
val vfLatencyStitchRunStat = libraryStatsReceiver.stat("vf_latency_stitch_run")
val visibilityDeciderGates = VisibilityDeciderGates(decider)
val verdictLogger = SearchVisibilityLibrary.createVerdictLogger(
visibilityDeciderGates.enableVerdictLoggerSVL,
decider,
libraryStatsReceiver)
val tweetLabels = safetyLabelMapSourceOption match {
case Some(safetyLabelMapSource) =>
new StratoTweetLabelMaps(safetyLabelMapSource)
case None =>
new StratoTweetLabelMaps(
SafetyLabelMapSource.fromStrato(stratoClient, stratoClientStatsReceiver))
}
val mediaLabelMaps = new StratoMediaLabelMaps(
MediaSafetyLabelMapSource.fromStrato(stratoClient, stratoClientStatsReceiver))
val tweetFeatures = new TweetFeatures(tweetLabels, libraryStatsReceiver)
val searchContextFeatures = new SearchContextFeatures(libraryStatsReceiver)
val authorFeatures = new AuthorFeatures(userSource, libraryStatsReceiver)
val viewerFeatures = new ViewerFeatures(userSource, libraryStatsReceiver)
val relationshipFeatures =
new RelationshipFeatures(userRelationshipSource, libraryStatsReceiver)
val misinfoPolicySource =
MisinformationPolicySource.fromStrato(stratoClient, stratoClientStatsReceiver)
val misinfoPolicyFeatures =
new MisinformationPolicyFeatures(misinfoPolicySource, stratoClientStatsReceiver)
val exclusiveTweetFeatures =
new ExclusiveTweetFeatures(userRelationshipSource, libraryStatsReceiver)
val mediaFeatures = new MediaFeatures(mediaLabelMaps, libraryStatsReceiver)
val trustedFriendsTweetFeatures = new TrustedFriendsFeatures(
trustedFriendsSource = TrustedFriendsSource.fromStrato(stratoClient, stratoClientStatsReceiver))
val editTweetFeatures = new EditTweetFeatures(libraryStatsReceiver)
def batchProcessSearchVisibilityRequest(
batchSvRequest: BatchSearchVisibilityRequest
): Stitch[BatchSearchVisibilityResponse] = {
val elapsed = Stopwatch.start()
svlRequestCounter.incr()
val response: Stitch[BatchSearchVisibilityResponse] =
batchSvRequest.tweetContexts.groupBy(tweetContext => tweetContext.safetyLevel) map {
case (safetyLevel: SafetyLevel, tweetContexts: Seq[TweetContext]) =>
val (contentsToBeEvaluated, contentVisResultTypes) =
extractContentsToBeEvaluated(tweetContexts, batchSvRequest.viewerContext)
getVisibilityResult(
contentsToBeEvaluated,
safetyLevel,
batchSvRequest.viewerContext,
batchSvRequest.searchVFRequestContext)
.map { contentVisResults: Seq[Try[VisibilityResult]] =>
(contentVisResultTypes zip contentVisResults)
.map(handleVisibilityResultByTweetType)
.groupBy {
case (requestTweetId: RequestTweetId, (_, _)) => requestTweetId
}.mapValues(combineVisibilityResult)
}.onSuccess(res =>
res.values.flatten.foreach(_ =>
SearchVisibilityLibrary.scribeVisibilityVerdict(
_,
visibilityDeciderGates.enableVerdictScribingSVL,
verdictLogger,
batchSvRequest.viewerContext.userId,
safetyLevel)))
} reduceLeft { (left, right) =>
Stitch.joinMap(left, right)((visResultsA, visResultsB) => visResultsA ++ visResultsB)
} map { visResults =>
val (succeed, failed) = visResults.partition { case (_, visResult) => visResult.nonEmpty }
val failedTweetIds: Seq[Long] = failed.keys.toSeq
BatchSearchVisibilityResponse(
visibilityResults = succeed.mapValues(visResult => visResult.get),
failedTweetIds = failedTweetIds
)
}
val runStitchStartMs = elapsed().inMilliseconds
val buildStitchStatMs = elapsed().inMilliseconds
vfLatencyStitchBuildStat.add(buildStitchStatMs)
response
.onSuccess(_ => {
val overallMs = elapsed().inMilliseconds
vfLatencyOverallStat.add(overallMs)
val stitchRunMs = elapsed().inMilliseconds - runStitchStartMs
vfLatencyStitchRunStat.add(stitchRunMs)
})
}
private def extractContentsToBeEvaluated(
tweetContexts: Seq[TweetContext],
viewerContext: ViewerContext
): (
Seq[(TweetContext, EvaluateTweetType, EvaluateTweet, ContentId)],
Seq[
(RequestTweetId, EvaluateTweetType)
]
) = {
val contentsToBeEvaluated: Seq[
(TweetContext, EvaluateTweetType, EvaluateTweet, ContentId)
] = tweetContexts.map(tc =>
(
tc,
REQUEST,
tc.tweet,
getContentId(
viewerId = viewerContext.userId,
authorId = tc.tweet.coreData.get.userId,
tweet = tc.tweet))) ++
tweetContexts
.filter(tc => tc.quotedTweet.nonEmpty).map(tc =>
(
tc,
QUOTED,
tc.quotedTweet.get,
getContentId(
viewerId = viewerContext.userId,
authorId = tc.quotedTweet.get.coreData.get.userId,
tweet = tc.quotedTweet.get))) ++
tweetContexts
.filter(tc => tc.retweetSourceTweet.nonEmpty).map(tc =>
(
tc,
SOURCE,
tc.retweetSourceTweet.get,
getContentId(
viewerId = viewerContext.userId,
authorId = tc.retweetSourceTweet.get.coreData.get.userId,
tweet = tc.retweetSourceTweet.get)))
val contentVisResultTypes: Seq[(RequestTweetId, EvaluateTweetType)] = {
contentsToBeEvaluated.map {
case (tc: TweetContext, tweetType: EvaluateTweetType, _, _) =>
(tc.tweet.id, tweetType)
}
}
(contentsToBeEvaluated, contentVisResultTypes)
}
private def combineVisibilityResult(
visResults: Seq[(RequestTweetId, (EvaluateTweetType, Try[VisibilityResult]))]
): Option[CombinedVisibilityResult] = {
visResults.sortBy(_._2._1)(ValueOrdering) match {
case Seq(
(_, (REQUEST, Return(requestTweetVisResult))),
(_, (QUOTED, Return(quotedTweetVisResult))),
(_, (SOURCE, Return(sourceTweetVisResult)))) =>
requestTweetVisResult.verdict match {
case Allow =>
Some(CombinedVisibilityResult(sourceTweetVisResult, Some(quotedTweetVisResult)))
case _ =>
Some(CombinedVisibilityResult(requestTweetVisResult, Some(quotedTweetVisResult)))
}
case Seq(
(_, (REQUEST, Return(requestTweetVisResult))),
(_, (QUOTED, Return(quotedTweetVisResult)))) =>
Some(CombinedVisibilityResult(requestTweetVisResult, Some(quotedTweetVisResult)))
case Seq(
(_, (REQUEST, Return(requestTweetVisResult))),
(_, (SOURCE, Return(sourceTweetVisResult)))) =>
requestTweetVisResult.verdict match {
case Allow =>
Some(CombinedVisibilityResult(sourceTweetVisResult, None))
case _ =>
Some(CombinedVisibilityResult(requestTweetVisResult, None))
}
case Seq((_, (REQUEST, Return(requestTweetVisResult)))) =>
Some(CombinedVisibilityResult(requestTweetVisResult, None))
case _ => None
}
}
private def getVisibilityResult(
contents: Seq[(TweetContext, EvaluateTweetType, EvaluateTweet, ContentId)],
safetyLevel: SafetyLevel,
viewerContext: ViewerContext,
svRequestContext: SearchVFRequestContext
): Stitch[Seq[Try[VisibilityResult]]] = {
val contentContext: Map[ContentId, (TweetContext, EvaluateTweetType, EvaluateTweet)] =
contents.map {
case (
tweetContext: TweetContext,
tweetType: EvaluateTweetType,
tweet: EvaluateTweet,
contentId: ContentId) =>
contentId -> ((tweetContext, tweetType, tweet))
}.toMap
val featureMapProvider: (ContentId, SafetyLevel) => FeatureMap = {
case (contentId: ContentId, _) =>
val (tweetContext, tweetType, tweet) = contentContext(contentId)
buildFeatureMap(
evaluatedTweet = tweet,
tweetType = tweetType,
tweetContext = tweetContext,
viewerContext = viewerContext,
svRequestContext = svRequestContext
)
}
visibilityLibrary.runRuleEngineBatch(
contentIds = contents.map { case (_, _, _, id: ContentId) => id },
featureMapProvider = featureMapProvider,
viewerContext = viewerContext,
safetyLevel = safetyLevel
)
}
private def getContentId(viewerId: Option[Long], authorId: Long, tweet: Tweet): ContentId = {
if (viewerId.contains(authorId))
TweetId(tweet.id)
else BlenderTweetId(tweet.id)
}
private def buildFeatureMap(
evaluatedTweet: Tweet,
tweetType: EvaluateTweetType,
tweetContext: TweetContext,
viewerContext: ViewerContext,
svRequestContext: SearchVFRequestContext
): FeatureMap = {
val authorId = evaluatedTweet.coreData.get.userId
val viewerId = viewerContext.userId
val isRetweet =
if (tweetType.equals(REQUEST)) tweetContext.retweetSourceTweet.nonEmpty else false
val isSourceTweet = tweetType.equals(SOURCE)
val isQuotedTweet = tweetType.equals(QUOTED)
val tweetMediaKeys: Seq[GenericMediaKey] = evaluatedTweet.media
.getOrElse(Seq.empty)
.flatMap(_.mediaKey.map(GenericMediaKey.apply))
visibilityLibrary.featureMapBuilder(
Seq(
viewerFeatures
.forViewerSearchContext(svRequestContext, viewerContext),
relationshipFeatures.forAuthorId(authorId, viewerId),
tweetFeatures.forTweet(evaluatedTweet),
mediaFeatures.forMediaKeys(tweetMediaKeys),
authorFeatures.forAuthorId(authorId),
searchContextFeatures.forSearchContext(svRequestContext),
_.withConstantFeature(TweetIsRetweet, isRetweet),
misinfoPolicyFeatures.forTweet(evaluatedTweet, viewerContext),
exclusiveTweetFeatures.forTweet(evaluatedTweet, viewerContext),
trustedFriendsTweetFeatures.forTweet(evaluatedTweet, viewerId),
editTweetFeatures.forTweet(evaluatedTweet),
_.withConstantFeature(TweetIsInnerQuotedTweet, isQuotedTweet),
_.withConstantFeature(TweetIsSourceTweet, isSourceTweet),
)
)
}
private def handleVisibilityResultByTweetType(
zipVisResult: ((RequestTweetId, EvaluateTweetType), Try[VisibilityResult])
): (RequestTweetId, (EvaluateTweetType, Try[VisibilityResult])) = {
zipVisResult match {
case ((id: RequestTweetId, REQUEST), Return(visResult)) =>
(id, (REQUEST, Return(handleComposableVisibilityResult(visResult))))
case ((id: RequestTweetId, QUOTED), Return(visResult)) =>
(
id,
(
QUOTED,
Return(
handleInnerQuotedTweetVisibilityResult(handleComposableVisibilityResult(visResult)))))
case ((id: RequestTweetId, SOURCE), Return(visResult)) =>
(id, (SOURCE, Return(handleComposableVisibilityResult(visResult))))
case ((id: RequestTweetId, tweetType: EvaluateTweetType), result: Try[VisibilityResult]) =>
(id, (tweetType, result))
}
}
private def handleComposableVisibilityResult(result: VisibilityResult): VisibilityResult = {
if (result.secondaryVerdicts.nonEmpty) {
result.copy(verdict = composeActions(result.verdict, result.secondaryVerdicts))
} else {
result
}
}
private def composeActions(primary: Action, secondary: Seq[Action]): Action = {
if (primary.isComposable && secondary.nonEmpty) {
val actions = Seq[Action] { primary } ++ secondary
val interstitialOpt = Action.getFirstInterstitial(actions: _*)
val softInterventionOpt = Action.getFirstSoftIntervention(actions: _*)
val limitedEngagementsOpt = Action.getFirstLimitedEngagements(actions: _*)
val avoidOpt = Action.getFirstAvoid(actions: _*)
val numActions =
Seq[Option[_]](interstitialOpt, softInterventionOpt, limitedEngagementsOpt, avoidOpt)
.count(_.isDefined)
if (numActions > 1) {
TweetInterstitial(
interstitialOpt,
softInterventionOpt,
limitedEngagementsOpt,
None,
avoidOpt
)
} else {
primary
}
} else {
primary
}
}
private def handleInnerQuotedTweetVisibilityResult(
result: VisibilityResult
): VisibilityResult = {
val newVerdict: Action =
result.verdict match {
case interstitial: Interstitial => Drop(interstitial.reason)
case ComposableActionsWithInterstitial(tweetInterstitial) => Drop(tweetInterstitial.reason)
case verdict => verdict
}
result.copy(verdict = newVerdict)
}
}

View File

@ -1,10 +0,0 @@
package com.twitter.visibility.interfaces.search
import com.twitter.tweetypie.thriftscala.Tweet
import com.twitter.visibility.models.SafetyLevel
case class TweetContext(
tweet: Tweet,
quotedTweet: Option[Tweet],
retweetSourceTweet: Option[Tweet] = None,
safetyLevel: SafetyLevel)

View File

@ -1,37 +0,0 @@
scala_library(
sources = ["*.scala"],
compiler_option_sets = ["fatal_warnings"],
platform = "java8",
strict_deps = True,
tags = ["bazel-compatible"],
dependencies = [
"decider/src/main/scala",
"servo/decider/src/main/scala",
"src/scala/com/twitter/search/blender/services/strato",
"src/thrift/com/twitter/escherbird:media-annotation-structs-scala",
"src/thrift/com/twitter/gizmoduck:user-thrift-scala",
"src/thrift/com/twitter/spam/rtf:safety-level-scala",
"src/thrift/com/twitter/spam/rtf:tweet-rtf-event-scala",
"src/thrift/com/twitter/tweetypie:tweet-scala",
"stitch/stitch-core",
"strato/src/main/scala/com/twitter/strato/client",
"visibility/common/src/main/scala/com/twitter/visibility/common",
"visibility/common/src/main/scala/com/twitter/visibility/common/stitch",
"visibility/lib/src/main/resources/config",
"visibility/lib/src/main/scala/com/twitter/visibility",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/common",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/spaces",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/tweets",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/users",
"visibility/lib/src/main/scala/com/twitter/visibility/configapi/configs",
"visibility/lib/src/main/scala/com/twitter/visibility/features",
"visibility/lib/src/main/scala/com/twitter/visibility/interfaces/common/tweets",
"visibility/lib/src/main/scala/com/twitter/visibility/rules/providers",
"visibility/lib/src/main/scala/com/twitter/visibility/rules/utils",
"visibility/lib/src/main/scala/com/twitter/visibility/util",
],
exports = [
"visibility/common/src/main/scala/com/twitter/visibility/common",
"visibility/lib/src/main/scala/com/twitter/visibility",
],
)

View File

@ -1,117 +0,0 @@
package com.twitter.visibility.interfaces.spaces
import com.twitter.servo.util.Gate
import com.twitter.stitch.Stitch
import com.twitter.strato.client.{Client => StratoClient}
import com.twitter.visibility.VisibilityLibrary
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.builder.common.MutedKeywordFeatures
import com.twitter.visibility.builder.spaces.SpaceFeatures
import com.twitter.visibility.builder.spaces.StratoSpaceLabelMaps
import com.twitter.visibility.builder.users.AuthorFeatures
import com.twitter.visibility.builder.users.RelationshipFeatures
import com.twitter.visibility.builder.users.ViewerFeatures
import com.twitter.visibility.common._
import com.twitter.visibility.common.stitch.StitchHelpers
import com.twitter.visibility.features.FeatureMap
import com.twitter.visibility.models.ContentId.SpaceId
import com.twitter.visibility.models.ContentId.SpacePlusUserId
import com.twitter.visibility.rules.EvaluationContext
import com.twitter.visibility.rules.providers.ProvidedEvaluationContext
import com.twitter.visibility.rules.utils.ShimUtils
object SpaceVisibilityLibrary {
type Type = SpaceVisibilityRequest => Stitch[VisibilityResult]
def apply(
visibilityLibrary: VisibilityLibrary,
stratoClient: StratoClient,
userSource: UserSource,
userRelationshipSource: UserRelationshipSource,
enableVfFeatureHydrationSpaceShim: Gate[Unit] = Gate.False
): Type = {
val libraryStatsReceiver = visibilityLibrary.statsReceiver
val stratoClientStatsReceiver = visibilityLibrary.statsReceiver.scope("strato")
val vfLatencyStatsReceiver = visibilityLibrary.statsReceiver.scope("vf_latency")
val vfEngineCounter = libraryStatsReceiver.counter("vf_engine_requests")
val spaceLabelMaps = new StratoSpaceLabelMaps(
SpaceSafetyLabelMapSource.fromStrato(stratoClient, stratoClientStatsReceiver),
libraryStatsReceiver)
val audioSpaceSource = AudioSpaceSource.fromStrato(stratoClient, stratoClientStatsReceiver)
val viewerFeatures = new ViewerFeatures(userSource, libraryStatsReceiver)
val authorFeatures = new AuthorFeatures(userSource, libraryStatsReceiver)
val relationshipFeatures =
new RelationshipFeatures(userRelationshipSource, libraryStatsReceiver)
val mutedKeywordFeatures = new MutedKeywordFeatures(
userSource,
userRelationshipSource,
KeywordMatcher.matcher(libraryStatsReceiver),
libraryStatsReceiver,
Gate.False
)
val spaceFeatures =
new SpaceFeatures(
spaceLabelMaps,
authorFeatures,
relationshipFeatures,
mutedKeywordFeatures,
audioSpaceSource)
{ r: SpaceVisibilityRequest =>
vfEngineCounter.incr()
val isVfFeatureHydrationEnabled = enableVfFeatureHydrationSpaceShim()
val viewerId = r.viewerContext.userId
val authorIds: Option[Seq[Long]] = r.spaceHostAndAdminUserIds
val contentId = {
(viewerId, authorIds) match {
case (Some(viewer), Some(authors)) if authors.contains(viewer) => SpaceId(r.spaceId)
case _ => SpacePlusUserId(r.spaceId)
}
}
val featureMap =
visibilityLibrary.featureMapBuilder(
Seq(
spaceFeatures.forSpaceAndAuthorIds(r.spaceId, viewerId, authorIds),
viewerFeatures.forViewerContext(r.viewerContext),
)
)
val resp = if (isVfFeatureHydrationEnabled) {
val evaluationContext = ProvidedEvaluationContext.injectRuntimeRulesIntoEvaluationContext(
evaluationContext = EvaluationContext(
r.safetyLevel,
visibilityLibrary.getParams(r.viewerContext, r.safetyLevel),
visibilityLibrary.statsReceiver)
)
val preFilteredFeatureMap =
ShimUtils.preFilterFeatureMap(featureMap, r.safetyLevel, contentId, evaluationContext)
FeatureMap
.resolve(preFilteredFeatureMap, libraryStatsReceiver).flatMap { resolvedFeatureMap =>
visibilityLibrary
.runRuleEngine(
contentId,
resolvedFeatureMap,
r.viewerContext,
r.safetyLevel
)
}
} else {
visibilityLibrary
.runRuleEngine(
contentId,
featureMap,
r.viewerContext,
r.safetyLevel
)
}
StitchHelpers.profileStitch(resp, Seq(vfLatencyStatsReceiver))
}
}
}

View File

@ -1,10 +0,0 @@
package com.twitter.visibility.interfaces.spaces
import com.twitter.visibility.models.SafetyLevel
import com.twitter.visibility.models.ViewerContext
case class SpaceVisibilityRequest(
spaceId: String,
safetyLevel: SafetyLevel,
viewerContext: ViewerContext,
spaceHostAndAdminUserIds: Option[Seq[Long]])

View File

@ -1,47 +0,0 @@
scala_library(
sources = ["*.scala"],
compiler_option_sets = ["fatal_warnings"],
platform = "java8",
strict_deps = True,
tags = ["bazel-compatible"],
dependencies = [
"3rdparty/jvm/com/twitter/src/java/com/twitter/logpipeline/client:logpipeline-event-publisher-thin",
"decider/src/main/scala",
"featureswitches/featureswitches-core/src/main/scala",
"mediaservices/media-util/src/main/scala",
"servo/decider/src/main/scala",
"src/thrift/com/twitter/context:twitter-context-scala",
"src/thrift/com/twitter/escherbird:media-annotation-structs-scala",
"src/thrift/com/twitter/gizmoduck:user-thrift-scala",
"src/thrift/com/twitter/spam/rtf:safety-level-scala",
"src/thrift/com/twitter/spam/rtf:tweet-rtf-event-scala",
"src/thrift/com/twitter/tweetypie:tweet-scala",
"stitch/stitch-core",
"strato/src/main/scala/com/twitter/strato/catalog",
"strato/src/main/scala/com/twitter/strato/client",
"twitter-context/src/main/scala",
"visibility/common/src/main/scala/com/twitter/visibility/common",
"visibility/common/src/main/scala/com/twitter/visibility/common/actions/converter/scala",
"visibility/common/src/main/scala/com/twitter/visibility/common/tweets",
"visibility/common/src/main/thrift/com/twitter/visibility/tweets:tweets-scala",
"visibility/lib/src/main/resources/config",
"visibility/lib/src/main/scala/com/twitter/visibility",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/common",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/media",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/tweets",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/users",
"visibility/lib/src/main/scala/com/twitter/visibility/configapi/configs",
"visibility/lib/src/main/scala/com/twitter/visibility/features",
"visibility/lib/src/main/scala/com/twitter/visibility/generators",
"visibility/lib/src/main/scala/com/twitter/visibility/interfaces/common/tweets",
"visibility/lib/src/main/scala/com/twitter/visibility/interfaces/tweets/enrichments",
"visibility/lib/src/main/scala/com/twitter/visibility/rules/providers",
"visibility/lib/src/main/scala/com/twitter/visibility/rules/utils",
"visibility/lib/src/main/scala/com/twitter/visibility/util",
"visibility/lib/src/main/thrift/com/twitter/visibility/logging:vf-logging-scala",
],
exports = [
"visibility/common/src/main/scala/com/twitter/visibility/common",
"visibility/lib/src/main/scala/com/twitter/visibility",
],
)

View File

@ -1,59 +0,0 @@
package com.twitter.visibility.interfaces.tweets
import com.twitter.decider.Decider
import com.twitter.stitch.Stitch
import com.twitter.visibility.VisibilityLibrary
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.features.TweetDeleteReason
import com.twitter.visibility.features.TweetIsInnerQuotedTweet
import com.twitter.visibility.features.TweetIsRetweet
import com.twitter.visibility.generators.TombstoneGenerator
import com.twitter.visibility.models.ContentId.DeleteTweetId
import com.twitter.visibility.models.SafetyLevel
import com.twitter.visibility.models.TweetDeleteReason.TweetDeleteReason
import com.twitter.visibility.models.ViewerContext
object DeletedTweetVisibilityLibrary {
type Type = DeletedTweetVisibilityLibrary.Request => Stitch[VisibilityResult]
case class Request(
tweetId: Long,
safetyLevel: SafetyLevel,
viewerContext: ViewerContext,
tweetDeleteReason: TweetDeleteReason,
isRetweet: Boolean,
isInnerQuotedTweet: Boolean,
)
def apply(
visibilityLibrary: VisibilityLibrary,
decider: Decider,
tombstoneGenerator: TombstoneGenerator,
): Type = {
val vfEngineCounter = visibilityLibrary.statsReceiver.counter("vf_engine_requests")
(request: Request) => {
vfEngineCounter.incr()
val contentId = DeleteTweetId(request.tweetId)
val language = request.viewerContext.requestLanguageCode.getOrElse("en")
val featureMap =
visibilityLibrary.featureMapBuilder(
Seq(
_.withConstantFeature(TweetIsInnerQuotedTweet, request.isInnerQuotedTweet),
_.withConstantFeature(TweetIsRetweet, request.isRetweet),
_.withConstantFeature(TweetDeleteReason, request.tweetDeleteReason)
)
)
visibilityLibrary
.runRuleEngine(
contentId,
featureMap,
request.viewerContext,
request.safetyLevel
)
.map(tombstoneGenerator(_, language))
}
}
}

View File

@ -1,150 +0,0 @@
package com.twitter.visibility.interfaces.tweets
import com.twitter.decider.Decider
import com.twitter.servo.util.Gate
import com.twitter.stitch.Stitch
import com.twitter.visibility.VisibilityLibrary
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.builder.users.AuthorFeatures
import com.twitter.visibility.builder.users.QuotedTweetFeatures
import com.twitter.visibility.builder.users.RelationshipFeatures
import com.twitter.visibility.builder.users.ViewerFeatures
import com.twitter.visibility.common.UserRelationshipSource
import com.twitter.visibility.common.UserSource
import com.twitter.visibility.configapi.configs.VisibilityDeciderGates
import com.twitter.visibility.features.FeatureMap
import com.twitter.visibility.models.ContentId.QuotedTweetRelationship
import com.twitter.visibility.models.SafetyLevel
import com.twitter.visibility.models.UserUnavailableStateEnum
import com.twitter.visibility.models.ViewerContext
import com.twitter.visibility.rules.Drop
import com.twitter.visibility.rules.EvaluationContext
import com.twitter.visibility.rules.Reason.AuthorBlocksViewer
import com.twitter.visibility.rules.Reason.DeactivatedAuthor
import com.twitter.visibility.rules.Reason.ErasedAuthor
import com.twitter.visibility.rules.Reason.OffboardedAuthor
import com.twitter.visibility.rules.Reason.ProtectedAuthor
import com.twitter.visibility.rules.Reason.SuspendedAuthor
import com.twitter.visibility.rules.Reason.ViewerBlocksAuthor
import com.twitter.visibility.rules.Reason.ViewerHardMutedAuthor
import com.twitter.visibility.rules.Reason.ViewerMutesAuthor
import com.twitter.visibility.rules.providers.ProvidedEvaluationContext
import com.twitter.visibility.rules.utils.ShimUtils
case class TweetAndAuthor(tweetId: Long, authorId: Long)
case class QuotedTweetVisibilityRequest(
quotedTweet: TweetAndAuthor,
outerTweet: TweetAndAuthor,
viewerContext: ViewerContext,
safetyLevel: SafetyLevel)
object QuotedTweetVisibilityLibrary {
type Type = QuotedTweetVisibilityRequest => Stitch[VisibilityResult]
def apply(
visibilityLibrary: VisibilityLibrary,
userSource: UserSource,
userRelationshipSource: UserRelationshipSource,
decider: Decider,
userStateVisibilityLibrary: UserUnavailableStateVisibilityLibrary.Type,
enableVfFeatureHydration: Gate[Unit] = Gate.False
): Type = {
val libraryStatsReceiver = visibilityLibrary.statsReceiver
val visibilityDeciderGates = VisibilityDeciderGates(decider)
val vfEngineCounter = libraryStatsReceiver.counter("vf_engine_requests")
{
case QuotedTweetVisibilityRequest(quotedTweet, outerTweet, viewerContext, safetyLevel) =>
vfEngineCounter.incr()
val contentId = QuotedTweetRelationship(
outer = outerTweet.tweetId,
inner = quotedTweet.tweetId
)
val innerAuthorId = quotedTweet.authorId
val outerAuthorId = outerTweet.authorId
val viewerId = viewerContext.userId
val isFeatureHydrationInShimEnabled = enableVfFeatureHydration()
val authorFeatures = new AuthorFeatures(userSource, libraryStatsReceiver)
val viewerFeatures = new ViewerFeatures(userSource, libraryStatsReceiver)
val relationshipFeatures =
new RelationshipFeatures(userRelationshipSource, libraryStatsReceiver)
val quotedTweetFeatures =
new QuotedTweetFeatures(relationshipFeatures, libraryStatsReceiver)
val featureMap = visibilityLibrary.featureMapBuilder(
Seq(
viewerFeatures.forViewerContext(viewerContext),
authorFeatures.forAuthorId(innerAuthorId),
relationshipFeatures.forAuthorId(innerAuthorId, viewerId),
quotedTweetFeatures.forOuterAuthor(outerAuthorId, innerAuthorId)
)
)
val resp = if (isFeatureHydrationInShimEnabled) {
val evaluationContext = ProvidedEvaluationContext.injectRuntimeRulesIntoEvaluationContext(
evaluationContext = EvaluationContext(
SafetyLevel.QuotedTweetRules,
visibilityLibrary.getParams(viewerContext, SafetyLevel.QuotedTweetRules),
visibilityLibrary.statsReceiver)
)
val preFilteredFeatureMap =
ShimUtils.preFilterFeatureMap(
featureMap,
SafetyLevel.QuotedTweetRules,
contentId,
evaluationContext)
FeatureMap.resolve(preFilteredFeatureMap, libraryStatsReceiver).flatMap {
resolvedFeatureMap =>
visibilityLibrary
.runRuleEngine(
contentId,
resolvedFeatureMap,
viewerContext,
SafetyLevel.QuotedTweetRules
)
}
} else {
visibilityLibrary
.runRuleEngine(
contentId,
featureMap,
viewerContext,
SafetyLevel.QuotedTweetRules
)
}
resp.flatMap { visResult =>
val userStateOpt = visResult.verdict match {
case Drop(DeactivatedAuthor, _) => Some(UserUnavailableStateEnum.Deactivated)
case Drop(OffboardedAuthor, _) => Some(UserUnavailableStateEnum.Offboarded)
case Drop(ErasedAuthor, _) => Some(UserUnavailableStateEnum.Erased)
case Drop(ProtectedAuthor, _) => Some(UserUnavailableStateEnum.Protected)
case Drop(SuspendedAuthor, _) => Some(UserUnavailableStateEnum.Suspended)
case Drop(AuthorBlocksViewer, _) => Some(UserUnavailableStateEnum.AuthorBlocksViewer)
case Drop(ViewerBlocksAuthor, _) => Some(UserUnavailableStateEnum.ViewerBlocksAuthor)
case Drop(ViewerMutesAuthor, _) => Some(UserUnavailableStateEnum.ViewerMutesAuthor)
case Drop(ViewerHardMutedAuthor, _) => Some(UserUnavailableStateEnum.ViewerMutesAuthor)
case _ => None
}
userStateOpt
.map(userState =>
userStateVisibilityLibrary(
UserUnavailableStateVisibilityRequest(
safetyLevel,
quotedTweet.tweetId,
viewerContext,
userState,
isRetweet = false,
isInnerQuotedTweet = true,
))).getOrElse(Stitch.value(visResult))
}
}
}
}

View File

@ -1,421 +0,0 @@
package com.twitter.visibility.interfaces.tweets
import com.twitter.decider.Decider
import com.twitter.featureswitches.v2.FeatureSwitches
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.mediaservices.media_util.GenericMediaKey
import com.twitter.servo.util.Gate
import com.twitter.stitch.Stitch
import com.twitter.strato.client.{Client => StratoClient}
import com.twitter.util.Stopwatch
import com.twitter.visibility.VisibilityLibrary
import com.twitter.visibility.builder.VerdictLogger
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.builder.common.MutedKeywordFeatures
import com.twitter.visibility.builder.media._
import com.twitter.visibility.builder.tweets.TweetVisibilityNudgeSourceWrapper
import com.twitter.visibility.builder.tweets._
import com.twitter.visibility.builder.users.AuthorFeatures
import com.twitter.visibility.builder.users.RelationshipFeatures
import com.twitter.visibility.builder.users.ViewerFeatures
import com.twitter.visibility.builder.users.ViewerSearchSafetyFeatures
import com.twitter.visibility.builder.users.ViewerSensitiveMediaSettingsFeatures
import com.twitter.visibility.common._
import com.twitter.visibility.common.actions.LimitedAction
import com.twitter.visibility.common.actions.LimitedActionType
import com.twitter.visibility.common.actions.LimitedActionsPolicy
import com.twitter.visibility.rules.ComposableActions._
import com.twitter.visibility.configapi.configs.VisibilityDeciderGates
import com.twitter.visibility.features.TweetIsInnerQuotedTweet
import com.twitter.visibility.features.TweetIsRetweet
import com.twitter.visibility.features.TweetIsSourceTweet
import com.twitter.visibility.generators.LocalizedInterstitialGenerator
import com.twitter.visibility.generators.TombstoneGenerator
import com.twitter.visibility.interfaces.tweets.enrichments.ComplianceTweetNoticeEnrichment
import com.twitter.visibility.interfaces.tweets.enrichments.LimitedActionsPolicyEnrichment
import com.twitter.visibility.interfaces.tweets.enrichments.TweetVisibilityNudgeEnrichment
import com.twitter.visibility.logging.thriftscala.VFLibType
import com.twitter.visibility.models.ContentId.TweetId
import com.twitter.visibility.models.SafetyLevel
import com.twitter.visibility.models.SafetyLevel.toThrift
import com.twitter.visibility.rules._
object TweetVisibilityLibrary {
type Type = TweetVisibilityRequest => Stitch[VisibilityResult]
def apply(
visibilityLibrary: VisibilityLibrary,
userSource: UserSource,
userRelationshipSource: UserRelationshipSource,
keywordMatcher: KeywordMatcher.Matcher,
invitedToConversationRepo: InvitedToConversationRepo,
decider: Decider,
stratoClient: StratoClient,
localizationSource: LocalizationSource,
tweetPerspectiveSource: TweetPerspectiveSource,
tweetMediaMetadataSource: TweetMediaMetadataSource,
tombstoneGenerator: TombstoneGenerator,
interstitialGenerator: LocalizedInterstitialGenerator,
limitedActionsFeatureSwitches: FeatureSwitches,
enableParityTest: Gate[Unit] = Gate.False
): Type = {
val libraryStatsReceiver = visibilityLibrary.statsReceiver
val stratoClientStatsReceiver = visibilityLibrary.statsReceiver.scope("strato")
val vfEngineCounter = libraryStatsReceiver.counter("vf_engine_requests")
val vfLatencyOverallStat = libraryStatsReceiver.stat("vf_latency_overall")
val vfLatencyStitchBuildStat = libraryStatsReceiver.stat("vf_latency_stitch_build")
val vfLatencyStitchRunStat = libraryStatsReceiver.stat("vf_latency_stitch_run")
val visibilityDeciderGates = VisibilityDeciderGates(decider)
val verdictLogger =
createVerdictLogger(
visibilityDeciderGates.enableVerdictLoggerTVL,
decider,
libraryStatsReceiver)
val tweetLabelMaps = new StratoTweetLabelMaps(
SafetyLabelMapSource.fromStrato(stratoClient, stratoClientStatsReceiver))
val mediaLabelMaps = new StratoMediaLabelMaps(
MediaSafetyLabelMapSource.fromStrato(stratoClient, stratoClientStatsReceiver))
val tweetFeatures = new TweetFeatures(tweetLabelMaps, libraryStatsReceiver)
val tweetPerspectiveFeatures =
new TweetPerspectiveFeatures(tweetPerspectiveSource, libraryStatsReceiver)
val mediaFeatures = new MediaFeatures(mediaLabelMaps, libraryStatsReceiver)
val tweetMediaMetadataFeatures =
new TweetMediaMetadataFeatures(tweetMediaMetadataSource, libraryStatsReceiver)
val authorFeatures = new AuthorFeatures(userSource, libraryStatsReceiver)
val viewerFeatures = new ViewerFeatures(userSource, libraryStatsReceiver)
val mutedKeywordFeatures =
new MutedKeywordFeatures(
userSource,
userRelationshipSource,
keywordMatcher,
libraryStatsReceiver,
visibilityDeciderGates.enableFollowCheckInMutedKeyword
)
val relationshipFeatures =
new RelationshipFeatures(userRelationshipSource, libraryStatsReceiver)
val fonsrRelationshipFeatures =
new FosnrRelationshipFeatures(
tweetLabels = tweetLabelMaps,
userRelationshipSource = userRelationshipSource,
statsReceiver = libraryStatsReceiver)
val conversationControlFeatures =
new ConversationControlFeatures(
relationshipFeatures,
invitedToConversationRepo,
libraryStatsReceiver
)
val exclusiveTweetFeatures =
new ExclusiveTweetFeatures(userRelationshipSource, libraryStatsReceiver)
val viewerSearchSafetyFeatures = new ViewerSearchSafetyFeatures(
UserSearchSafetySource.fromStrato(stratoClient, stratoClientStatsReceiver),
libraryStatsReceiver)
val viewerSensitiveMediaSettingsFeatures = new ViewerSensitiveMediaSettingsFeatures(
UserSensitiveMediaSettingsSource.fromStrato(stratoClient, stratoClientStatsReceiver),
libraryStatsReceiver)
val toxicReplyFilterFeature = new ToxicReplyFilterFeature(statsReceiver = libraryStatsReceiver)
val misinfoPolicySource =
MisinformationPolicySource.fromStrato(stratoClient, stratoClientStatsReceiver)
val misinfoPolicyFeatures =
new MisinformationPolicyFeatures(misinfoPolicySource, stratoClientStatsReceiver)
val communityTweetFeatures = new CommunityTweetFeaturesV2(
communitiesSource = CommunitiesSource.fromStrato(
stratoClient,
stratoClientStatsReceiver
)
)
val trustedFriendsTweetFeatures = new TrustedFriendsFeatures(
trustedFriendsSource =
TrustedFriendsSource.fromStrato(stratoClient, stratoClientStatsReceiver))
val editTweetFeatures = new EditTweetFeatures(libraryStatsReceiver)
val parityTest = new TweetVisibilityLibraryParityTest(libraryStatsReceiver, stratoClient)
val localizedNudgeSource =
LocalizedNudgeSource.fromLocalizationSource(localizationSource)
val tweetVisibilityNudgeFeatures =
new TweetVisibilityNudgeSourceWrapper(localizedNudgeSource)
val localizedLimitedActionsSource =
LocalizedLimitedActionsSource.fromLocalizationSource(localizationSource)
{ r: TweetVisibilityRequest =>
val elapsed = Stopwatch.start()
var runStitchStartMs = 0L
vfEngineCounter.incr()
val contentId = TweetId(r.tweet.id)
val viewerId = r.viewerContext.userId
val authorId = coreData.userId
val tweetGenericMediaKeys = r.tweet.mediaRefs
.getOrElse(Seq.empty)
.flatMap { mediaRef =>
GenericMediaKey.fromStringKey(mediaRef.genericMediaKey)
}
val tpf =
tweetPerspectiveFeatures.forTweet(
r.tweet,
viewerId,
visibilityDeciderGates.enableFetchTweetReportedPerspective())
val featureMap =
visibilityLibrary.featureMapBuilder(
Seq(
mutedKeywordFeatures.forTweet(r.tweet, viewerId, authorId),
viewerFeatures.forViewerContext(r.viewerContext),
viewerSearchSafetyFeatures.forViewerId(viewerId),
viewerSensitiveMediaSettingsFeatures.forViewerId(viewerId),
relationshipFeatures.forAuthorId(authorId, viewerId),
fonsrRelationshipFeatures
.forTweetAndAuthorId(tweet = r.tweet, authorId = authorId, viewerId = viewerId),
tweetFeatures.forTweet(r.tweet),
tpf,
mediaFeatures.forMediaKeys(tweetGenericMediaKeys),
authorFeatures.forAuthorId(authorId),
conversationControlFeatures.forTweet(r.tweet, viewerId),
_.withConstantFeature(TweetIsInnerQuotedTweet, r.isInnerQuotedTweet),
_.withConstantFeature(TweetIsRetweet, r.isRetweet),
_.withConstantFeature(TweetIsSourceTweet, r.isSourceTweet),
misinfoPolicyFeatures.forTweet(r.tweet, r.viewerContext),
exclusiveTweetFeatures.forTweet(r.tweet, r.viewerContext),
communityTweetFeatures.forTweet(r.tweet, r.viewerContext),
tweetMediaMetadataFeatures
.forTweet(
r.tweet,
tweetGenericMediaKeys,
visibilityDeciderGates.enableFetchTweetMediaMetadata()),
trustedFriendsTweetFeatures.forTweet(r.tweet, viewerId),
editTweetFeatures.forTweet(r.tweet),
toxicReplyFilterFeature.forTweet(r.tweet, viewerId),
)
)
val languageCode = r.viewerContext.requestLanguageCode.getOrElse("en")
val countryCode = r.viewerContext.requestCountryCode
val response = visibilityLibrary
.runRuleEngine(
contentId,
featureMap,
r.viewerContext,
r.safetyLevel
)
.map(
TweetVisibilityNudgeEnrichment(
_,
tweetVisibilityNudgeFeatures,
languageCode,
countryCode))
.map(verdict => {
if (visibilityDeciderGates.enableBackendLimitedActions()) {
LimitedActionsPolicyEnrichment(
verdict,
localizedLimitedActionsSource,
languageCode,
countryCode,
limitedActionsFeatureSwitches,
libraryStatsReceiver)
} else {
verdict
}
})
.map(
handleComposableVisibilityResult(
_,
visibilityDeciderGates.enableMediaInterstitialComposition(),
visibilityDeciderGates.enableBackendLimitedActions()))
.map(handleInnerQuotedTweetVisibilityResult(_, r.isInnerQuotedTweet))
.map(tombstoneGenerator(_, languageCode))
.map(interstitialGenerator(_, languageCode))
.map(ComplianceTweetNoticeEnrichment(_, libraryStatsReceiver))
.onSuccess(_ => {
val overallStatMs = elapsed().inMilliseconds
vfLatencyOverallStat.add(overallStatMs)
val runStitchEndMs = elapsed().inMilliseconds
vfLatencyStitchRunStat.add(runStitchEndMs - runStitchStartMs)
})
.onSuccess(
scribeVisibilityVerdict(
_,
visibilityDeciderGates.enableVerdictScribingTVL,
verdictLogger,
r.viewerContext.userId,
r.safetyLevel))
runStitchStartMs = elapsed().inMilliseconds
val buildStitchStatMs = elapsed().inMilliseconds
vfLatencyStitchBuildStat.add(buildStitchStatMs)
if (enableParityTest()) {
response.applyEffect { resp =>
Stitch.async(parityTest.runParityTest(r, resp))
}
} else {
response
}
}
}
def handleComposableVisibilityResult(
result: VisibilityResult,
enableMediaInterstitialComposition: Boolean,
enableBackendLimitedActions: Boolean
): VisibilityResult = {
if (result.secondaryVerdicts.nonEmpty || enableBackendLimitedActions) {
result.copy(verdict = composeActions(
result.verdict,
result.secondaryVerdicts,
enableMediaInterstitialComposition,
enableBackendLimitedActions))
} else {
result
}
}
def handleInnerQuotedTweetVisibilityResult(
result: VisibilityResult,
isInnerQuotedTweet: Boolean
): VisibilityResult = {
val newVerdict: Action =
result.verdict match {
case Interstitial(Reason.Nsfw | Reason.NsfwMedia, _, _) if isInnerQuotedTweet =>
Drop(Reason.Nsfw)
case ComposableActionsWithInterstitial(tweetInterstitial)
if isInnerQuotedTweet && (tweetInterstitial.reason == Reason.Nsfw || tweetInterstitial.reason == Reason.NsfwMedia) =>
Drop(Reason.Nsfw)
case verdict => verdict
}
result.copy(verdict = newVerdict)
}
def hasTweetRules(safetyLevel: SafetyLevel): Boolean = RuleBase.hasTweetRules(safetyLevel)
def composeActions(
primary: Action,
secondary: Seq[Action],
enableMediaInterstitialComposition: Boolean,
enableBackendLimitedActions: Boolean
): Action = {
if (primary.isComposable && (secondary.nonEmpty || enableBackendLimitedActions)) {
val actions = Seq[Action] { primary } ++ secondary
val interstitialOpt = Action.getFirstInterstitial(actions: _*)
val softInterventionOpt = Action.getFirstSoftIntervention(actions: _*)
val downrankOpt = Action.getFirstDownrankHomeTimeline(actions: _*)
val avoidOpt = Action.getFirstAvoid(actions: _*)
val tweetVisibilityNudgeOpt = Action.getFirstTweetVisibilityNudge(actions: _*)
val mediaInterstitialOpt = {
val firstMediaInterstitialOpt = Action.getFirstMediaInterstitial(actions: _*)
if (enableMediaInterstitialComposition && interstitialOpt != firstMediaInterstitialOpt) {
firstMediaInterstitialOpt
} else {
None
}
}
val limitedEngagementsOpt = enableBackendLimitedActions match {
case true => buildCompositeLimitedEngagements(Action.getAllLimitedEngagements(actions: _*))
case false => Action.getFirstLimitedEngagements(actions: _*)
}
val abusiveQualityOpt = {
if (actions.contains(ConversationSectionAbusiveQuality)) {
Some(ConversationSectionAbusiveQuality)
} else {
None
}
}
val numActions =
Seq[Option[_]](
interstitialOpt,
softInterventionOpt,
limitedEngagementsOpt,
downrankOpt,
avoidOpt,
mediaInterstitialOpt,
tweetVisibilityNudgeOpt,
abusiveQualityOpt)
.count(_.isDefined)
if (numActions > 1) {
TweetInterstitial(
interstitialOpt,
softInterventionOpt,
limitedEngagementsOpt,
downrankOpt,
avoidOpt,
mediaInterstitialOpt,
tweetVisibilityNudgeOpt,
abusiveQualityOpt
)
} else {
if (enableBackendLimitedActions) {
limitedEngagementsOpt.getOrElse(primary)
} else {
primary
}
}
} else {
primary
}
}
def scribeVisibilityVerdict(
result: VisibilityResult,
enableVerdictScribing: Gate[Unit],
verdictLogger: VerdictLogger,
viewerId: Option[Long],
safetyLevel: SafetyLevel
): Unit = if (enableVerdictScribing()) {
verdictLogger.scribeVerdict(
visibilityResult = result,
viewerId = viewerId,
safetyLevel = toThrift(safetyLevel),
vfLibType = VFLibType.TweetVisibilityLibrary)
}
def buildCompositeLimitedEngagements(
limitedEngagements: Seq[IsLimitedEngagements]
): Option[LimitedEngagements] = {
limitedEngagements.headOption.flatMap { limitedEngagement =>
val distinctLimitedActions = limitedEngagements
.collect({ case IsLimitedEngagements(Some(policy), _) => policy.limitedActions })
.flatten
.foldRight(Map.empty[LimitedActionType, LimitedAction])({ (limitedAction, acc) =>
acc + ((limitedAction.limitedActionType, limitedAction))
})
.values
.toSeq
if (distinctLimitedActions.nonEmpty) {
val limitedActionsPolicy = Some(LimitedActionsPolicy(distinctLimitedActions))
Some(LimitedEngagements(limitedEngagement.getLimitedEngagementReason, limitedActionsPolicy))
} else {
None
}
}
}
def createVerdictLogger(
enableVerdictLogger: Gate[Unit],
decider: Decider,
statsReceiver: StatsReceiver
): VerdictLogger = {
if (enableVerdictLogger()) {
VerdictLogger(statsReceiver, decider)
} else {
VerdictLogger.Empty
}
}
}

View File

@ -1,109 +0,0 @@
package com.twitter.visibility.interfaces.tweets
import com.twitter.spam.rtf.{thriftscala => t}
import com.twitter.context.TwitterContext
import com.twitter.context.thriftscala.Viewer
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.stitch.Stitch
import com.twitter.strato.catalog.Fetch
import com.twitter.strato.client.Client
import com.twitter.strato.client.Fetcher
import com.twitter.strato.thrift.ScroogeConvImplicits._
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.common.tweets.TweetVisibilityResultMapper
import com.twitter.visibility.models.SafetyLevel.toThrift
import com.twitter.visibility.models.ViewerContext
import com.twitter.visibility.thriftscala.TweetVisibilityResult
class TweetVisibilityLibraryParityTest(statsReceiver: StatsReceiver, stratoClient: Client) {
private val parityTestScope = statsReceiver.scope("tweet_visibility_library_parity")
private val requests = parityTestScope.counter("requests")
private val equal = parityTestScope.counter("equal")
private val incorrect = parityTestScope.counter("incorrect")
private val empty = parityTestScope.counter("empty")
private val failures = parityTestScope.counter("failures")
private val fetcher: Fetcher[Long, t.SafetyLevel, TweetVisibilityResult] =
stratoClient.fetcher[Long, t.SafetyLevel, TweetVisibilityResult](
"visibility/service/TweetVisibilityResult.Tweet"
)
def runParityTest(
req: TweetVisibilityRequest,
resp: VisibilityResult
): Stitch[Unit] = {
requests.incr()
val twitterContext = TwitterContext(TwitterContextPermit)
val viewer: Option[Viewer] = {
val remoteViewerContext = ViewerContext.fromContext
if (remoteViewerContext != req.viewerContext) {
val updatedRemoteViewerContext = remoteViewerContext.copy(
userId = req.viewerContext.userId
)
if (updatedRemoteViewerContext == req.viewerContext) {
twitterContext() match {
case None =>
Some(Viewer(userId = req.viewerContext.userId))
case Some(v) =>
Some(v.copy(userId = req.viewerContext.userId))
}
} else {
None
}
} else {
None
}
}
val tweetypieContext = TweetypieContext(
isQuotedTweet = req.isInnerQuotedTweet,
isRetweet = req.isRetweet,
hydrateConversationControl = req.hydrateConversationControl
)
val parityCheck: Stitch[Fetch.Result[TweetVisibilityResult]] = {
Stitch.callFuture {
TweetypieContext.let(tweetypieContext) {
viewer match {
case Some(viewer) =>
twitterContext.let(viewer) {
Stitch.run(fetcher.fetch(req.tweet.id, toThrift(req.safetyLevel)))
}
case None =>
Stitch.run(fetcher.fetch(req.tweet.id, toThrift(req.safetyLevel)))
}
}
}
}
parityCheck
.flatMap { parityResponse =>
val tvr = TweetVisibilityResultMapper.fromAction(resp.verdict.toActionThrift())
parityResponse.v match {
case Some(ptvr) =>
if (tvr == ptvr) {
equal.incr()
} else {
incorrect.incr()
}
case None =>
empty.incr()
}
Stitch.Done
}.rescue {
case t: Throwable =>
failures.incr()
Stitch.Done
}.unit
}
}

View File

@ -1,14 +0,0 @@
package com.twitter.visibility.interfaces.tweets
import com.twitter.tweetypie.thriftscala.Tweet
import com.twitter.visibility.models.SafetyLevel
import com.twitter.visibility.models.ViewerContext
case class TweetVisibilityRequest(
tweet: Tweet,
safetyLevel: SafetyLevel,
viewerContext: ViewerContext,
isInnerQuotedTweet: Boolean,
isRetweet: Boolean,
hydrateConversationControl: Boolean = false,
isSourceTweet: Boolean = false)

View File

@ -1,59 +0,0 @@
package com.twitter.visibility.interfaces.tweets
import com.twitter.finagle.context.Contexts
import com.twitter.io.Buf
import com.twitter.io.BufByteWriter
import com.twitter.io.ByteReader
import com.twitter.util.Future
import com.twitter.util.Return
import com.twitter.util.Throw
import com.twitter.util.Try
case class TweetypieContext(
isQuotedTweet: Boolean,
isRetweet: Boolean,
hydrateConversationControl: Boolean)
object TweetypieContext {
def let[U](value: TweetypieContext)(f: => Future[U]): Future[U] =
Contexts.broadcast.let(TweetypieContextKey, value)(f)
def get(): Option[TweetypieContext] =
Contexts.broadcast.get(TweetypieContextKey)
}
object TweetypieContextKey
extends Contexts.broadcast.Key[TweetypieContext](
"com.twitter.visibility.interfaces.tweets.TweetypieContext"
) {
override def marshal(value: TweetypieContext): Buf = {
val bw = BufByteWriter.fixed(1)
val byte =
((if (value.isQuotedTweet) 1 else 0) << 0) |
((if (value.isRetweet) 1 else 0) << 1) |
((if (value.hydrateConversationControl) 1 else 0) << 2)
bw.writeByte(byte)
bw.owned()
}
override def tryUnmarshal(buf: Buf): Try[TweetypieContext] = {
if (buf.length != 1) {
Throw(
new IllegalArgumentException(
s"Could not extract Boolean from Buf. Length ${buf.length} but required 1"
)
)
} else {
val byte: Byte = ByteReader(buf).readByte()
Return(
TweetypieContext(
isQuotedTweet = ((byte & 1) == 1),
isRetweet = ((byte & 2) == 2),
hydrateConversationControl = ((byte & 4) == 4)
)
)
}
}
}

View File

@ -1,138 +0,0 @@
package com.twitter.visibility.interfaces.tweets
import com.twitter.decider.Decider
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.stitch.Stitch
import com.twitter.visibility.VisibilityLibrary
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.builder.users.UserUnavailableFeatures
import com.twitter.visibility.common.actions.converter.scala.DropReasonConverter
import com.twitter.visibility.configapi.configs.VisibilityDeciderGates
import com.twitter.visibility.features.TweetIsInnerQuotedTweet
import com.twitter.visibility.features.TweetIsRetweet
import com.twitter.visibility.generators.LocalizedInterstitialGenerator
import com.twitter.visibility.generators.TombstoneGenerator
import com.twitter.visibility.models.ContentId.UserUnavailableState
import com.twitter.visibility.models.UserUnavailableStateEnum
import com.twitter.visibility.rules.Drop
import com.twitter.visibility.rules.Interstitial
import com.twitter.visibility.rules.Reason
import com.twitter.visibility.rules.Tombstone
import com.twitter.visibility.thriftscala.UserVisibilityResult
object UserUnavailableStateVisibilityLibrary {
type Type = UserUnavailableStateVisibilityRequest => Stitch[VisibilityResult]
def apply(
visibilityLibrary: VisibilityLibrary,
decider: Decider,
tombstoneGenerator: TombstoneGenerator,
interstitialGenerator: LocalizedInterstitialGenerator
): Type = {
val libraryStatsReceiver = visibilityLibrary.statsReceiver.scope("user_unavailable_vis_library")
val defaultDropScope = visibilityLibrary.statsReceiver.scope("default_drop")
val vfEngineCounter = libraryStatsReceiver.counter("vf_engine_requests")
val userUnavailableFeatures = UserUnavailableFeatures(libraryStatsReceiver)
val visibilityDeciderGates = VisibilityDeciderGates(decider)
{ r: UserUnavailableStateVisibilityRequest =>
vfEngineCounter.incr()
val contentId = UserUnavailableState(r.tweetId)
val featureMap =
visibilityLibrary.featureMapBuilder(
Seq(
_.withConstantFeature(TweetIsInnerQuotedTweet, r.isInnerQuotedTweet),
_.withConstantFeature(TweetIsRetweet, r.isRetweet),
userUnavailableFeatures.forState(r.userUnavailableState)
)
)
val language = r.viewerContext.requestLanguageCode.getOrElse("en")
val reason = visibilityLibrary
.runRuleEngine(
contentId,
featureMap,
r.viewerContext,
r.safetyLevel
).map(defaultToDrop(r.userUnavailableState, defaultDropScope))
.map(tombstoneGenerator(_, language))
.map(visibilityResult => {
if (visibilityDeciderGates.enableLocalizedInterstitialInUserStateLibrary()) {
interstitialGenerator(visibilityResult, language)
} else {
visibilityResult
}
})
reason
}
}
def defaultToDrop(
userUnavailableState: UserUnavailableStateEnum,
defaultDropScope: StatsReceiver
)(
result: VisibilityResult
): VisibilityResult =
result.verdict match {
case _: Drop | _: Tombstone => result
case _: Interstitial => result
case _ =>
result.copy(verdict =
Drop(userUnavailableStateToDropReason(userUnavailableState, defaultDropScope)))
}
private[this] def userUnavailableStateToDropReason(
userUnavailableState: UserUnavailableStateEnum,
stats: StatsReceiver
): Reason =
userUnavailableState match {
case UserUnavailableStateEnum.Erased =>
stats.counter("erased").incr()
Reason.ErasedAuthor
case UserUnavailableStateEnum.Protected =>
stats.counter("protected").incr()
Reason.ProtectedAuthor
case UserUnavailableStateEnum.Offboarded =>
stats.counter("offboarded").incr()
Reason.OffboardedAuthor
case UserUnavailableStateEnum.AuthorBlocksViewer =>
stats.counter("author_blocks_viewer").incr()
Reason.AuthorBlocksViewer
case UserUnavailableStateEnum.Suspended =>
stats.counter("suspended_author").incr()
Reason.SuspendedAuthor
case UserUnavailableStateEnum.Deactivated =>
stats.counter("deactivated_author").incr()
Reason.DeactivatedAuthor
case UserUnavailableStateEnum.Filtered(result) =>
stats.counter("filtered").incr()
userVisibilityResultToDropReason(result, stats.scope("filtered"))
case UserUnavailableStateEnum.Unavailable =>
stats.counter("unspecified").incr()
Reason.Unspecified
case _ =>
stats.counter("unknown").incr()
stats.scope("unknown").counter(userUnavailableState.name).incr()
Reason.Unspecified
}
private[this] def userVisibilityResultToDropReason(
result: UserVisibilityResult,
stats: StatsReceiver
): Reason =
result.action
.flatMap(DropReasonConverter.fromAction)
.map { dropReason =>
val reason = Reason.fromDropReason(dropReason)
stats.counter(reason.name).incr()
reason
}.getOrElse {
stats.counter("empty")
Reason.Unspecified
}
}

View File

@ -1,14 +0,0 @@
package com.twitter.visibility.interfaces.tweets
import com.twitter.visibility.models.UserUnavailableStateEnum
import com.twitter.visibility.models.SafetyLevel
import com.twitter.visibility.models.ViewerContext
case class UserUnavailableStateVisibilityRequest(
safetyLevel: SafetyLevel,
tweetId: Long,
viewerContext: ViewerContext,
userUnavailableState: UserUnavailableStateEnum,
isRetweet: Boolean,
isInnerQuotedTweet: Boolean,
)

View File

@ -1,25 +0,0 @@
scala_library(
sources = ["*.scala"],
compiler_option_sets = ["fatal_warnings"],
platform = "java8",
strict_deps = True,
tags = ["bazel-compatible"],
dependencies = [
"featureswitches/featureswitches-core/src/main/scala",
"src/thrift/com/twitter/spam/rtf:safety-result-scala",
"stitch/stitch-core",
"visibility/common/src/main/scala/com/twitter/visibility/common",
"visibility/common/src/main/scala/com/twitter/visibility/common/actions",
"visibility/common/src/main/scala/com/twitter/visibility/common/actions/converter/scala",
"visibility/lib/src/main/scala/com/twitter/visibility",
"visibility/lib/src/main/scala/com/twitter/visibility/builder",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/tweets",
"visibility/lib/src/main/scala/com/twitter/visibility/features",
"visibility/lib/src/main/scala/com/twitter/visibility/rules",
"visibility/results/src/main/scala/com/twitter/visibility/results/richtext",
],
exports = [
"featureswitches/featureswitches-core/src/main/scala",
"visibility/lib/src/main/scala/com/twitter/visibility/builder",
],
)

View File

@ -1,55 +0,0 @@
package com.twitter.visibility.interfaces.tweets.enrichments
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.results.richtext.PublicInterestReasonToPlainText
import com.twitter.visibility.rules.Action
import com.twitter.visibility.rules.ComplianceTweetNoticePreEnrichment
import com.twitter.visibility.rules.PublicInterest
import com.twitter.visibility.rules.Reason
object ComplianceTweetNoticeEnrichment {
val ComplianceTweetNoticeEnrichmentScope = "compliance_tweet_notice_enrichment"
val ComplianceTweetNoticePreEnrichmentActionScope =
"compliance_tweet_notice_pre_enrichment_action"
val englishLanguageTag = "en"
def apply(result: VisibilityResult, statsReceiver: StatsReceiver): VisibilityResult = {
val scopedStatsReceiver = statsReceiver.scope(ComplianceTweetNoticeEnrichmentScope)
val enrichedVerdict = enrichVerdict(result.verdict, scopedStatsReceiver)
result.copy(verdict = enrichedVerdict)
}
private def enrichVerdict(
verdict: Action,
statsReceiver: StatsReceiver
): Action = {
val preEnrichmentActionScope =
statsReceiver.scope(ComplianceTweetNoticePreEnrichmentActionScope)
verdict match {
case complianceTweetNoticePreEnrichmentVerdict: ComplianceTweetNoticePreEnrichment =>
preEnrichmentActionScope.counter("").incr()
val verdictWithDetailsAndUrl = complianceTweetNoticePreEnrichmentVerdict.reason match {
case Reason.Unspecified =>
preEnrichmentActionScope.counter("reason_unspecified").incr()
complianceTweetNoticePreEnrichmentVerdict
case reason =>
preEnrichmentActionScope.counter("reason_specified").incr()
val safetyResultReason = PublicInterest.ReasonToSafetyResultReason(reason)
val (details, url) =
PublicInterestReasonToPlainText(safetyResultReason, englishLanguageTag)
complianceTweetNoticePreEnrichmentVerdict.copy(
details = Some(details),
extendedDetailsUrl = Some(url))
}
verdictWithDetailsAndUrl.toComplianceTweetNotice()
case _ => verdict
}
}
}

View File

@ -1,173 +0,0 @@
package com.twitter.visibility.interfaces.tweets.enrichments
import com.twitter.featureswitches.FSRecipient
import com.twitter.featureswitches.v2.FeatureSwitches
import com.twitter.finagle.stats.StatsReceiver
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.common.LocalizedLimitedActionsSource
import com.twitter.visibility.common.actions.converter.scala.LimitedActionTypeConverter
import com.twitter.visibility.common.actions.LimitedActionsPolicy
import com.twitter.visibility.common.actions.LimitedActionType
import com.twitter.visibility.common.actions.LimitedEngagementReason
import com.twitter.visibility.rules.Action
import com.twitter.visibility.rules.EmergencyDynamicInterstitial
import com.twitter.visibility.rules.InterstitialLimitedEngagements
import com.twitter.visibility.rules.LimitedEngagements
case class PolicyFeatureSwitchResults(
limitedActionTypes: Option[Seq[LimitedActionType]],
copyNamespace: String,
promptType: String,
learnMoreUrl: Option[String])
object LimitedActionsPolicyEnrichment {
object FeatureSwitchKeys {
val LimitedActionTypes = "limited_actions_policy_limited_actions"
val CopyNamespace = "limited_actions_policy_copy_namespace"
val PromptType = "limited_actions_policy_prompt_type"
val LearnMoreUrl = "limited_actions_policy_prompt_learn_more_url"
}
val DefaultCopyNameSpace = "Default"
val DefaultPromptType = "basic"
val LimitedActionsPolicyEnrichmentScope = "limited_actions_policy_enrichment"
val MissingLimitedActionTypesScope = "missing_limited_action_types"
val ExecutedScope = "executed"
def apply(
result: VisibilityResult,
localizedLimitedActionSource: LocalizedLimitedActionsSource,
languageCode: String,
countryCode: Option[String],
featureSwitches: FeatureSwitches,
statsReceiver: StatsReceiver
): VisibilityResult = {
val scopedStatsReceiver = statsReceiver.scope(LimitedActionsPolicyEnrichmentScope)
val enrichVerdict_ = enrichVerdict(
_: Action,
localizedLimitedActionSource,
languageCode,
countryCode,
featureSwitches,
scopedStatsReceiver
)
result.copy(
verdict = enrichVerdict_(result.verdict),
secondaryVerdicts = result.secondaryVerdicts.map(enrichVerdict_)
)
}
private def enrichVerdict(
verdict: Action,
localizedLimitedActionsSource: LocalizedLimitedActionsSource,
languageCode: String,
countryCode: Option[String],
featureSwitches: FeatureSwitches,
statsReceiver: StatsReceiver
): Action = {
val limitedActionsPolicyForReason_ = limitedActionsPolicyForReason(
_: LimitedEngagementReason,
localizedLimitedActionsSource,
languageCode,
countryCode,
featureSwitches,
statsReceiver
)
val executedCounter = statsReceiver.scope(ExecutedScope)
verdict match {
case le: LimitedEngagements => {
executedCounter.counter("").incr()
executedCounter.counter(le.name).incr()
le.copy(
policy = limitedActionsPolicyForReason_(le.getLimitedEngagementReason)
)
}
case ile: InterstitialLimitedEngagements => {
executedCounter.counter("").incr()
executedCounter.counter(ile.name).incr()
ile.copy(
policy = limitedActionsPolicyForReason_(
ile.getLimitedEngagementReason
)
)
}
case edi: EmergencyDynamicInterstitial => {
executedCounter.counter("").incr()
executedCounter.counter(edi.name).incr()
EmergencyDynamicInterstitial(
copy = edi.copy,
linkOpt = edi.linkOpt,
localizedMessage = edi.localizedMessage,
policy = limitedActionsPolicyForReason_(edi.getLimitedEngagementReason)
)
}
case _ => verdict
}
}
private def limitedActionsPolicyForReason(
reason: LimitedEngagementReason,
localizedLimitedActionsSource: LocalizedLimitedActionsSource,
languageCode: String,
countryCode: Option[String],
featureSwitches: FeatureSwitches,
statsReceiver: StatsReceiver
): Option[LimitedActionsPolicy] = {
val policyConfig = getPolicyFeatureSwitchResults(featureSwitches, reason)
policyConfig.limitedActionTypes match {
case Some(limitedActionTypes) if limitedActionTypes.nonEmpty =>
Some(
LimitedActionsPolicy(
limitedActionTypes.map(
localizedLimitedActionsSource.fetch(
_,
languageCode,
countryCode,
policyConfig.promptType,
policyConfig.copyNamespace,
policyConfig.learnMoreUrl
)
)
)
)
case _ => {
statsReceiver
.scope(MissingLimitedActionTypesScope).counter(reason.toLimitedActionsString).incr()
None
}
}
}
private def getPolicyFeatureSwitchResults(
featureSwitches: FeatureSwitches,
reason: LimitedEngagementReason
): PolicyFeatureSwitchResults = {
val recipient = FSRecipient().withCustomFields(
("LimitedEngagementReason", reason.toLimitedActionsString)
)
val featureSwitchesResults = featureSwitches
.matchRecipient(recipient)
val limitedActionTypes = featureSwitchesResults
.getStringArray(FeatureSwitchKeys.LimitedActionTypes)
.map(_.map(LimitedActionTypeConverter.fromString).flatten)
val copyNamespace = featureSwitchesResults
.getString(FeatureSwitchKeys.CopyNamespace)
.getOrElse(DefaultCopyNameSpace)
val promptType = featureSwitchesResults
.getString(FeatureSwitchKeys.PromptType)
.getOrElse(DefaultPromptType)
val learnMoreUrl = featureSwitchesResults
.getString(FeatureSwitchKeys.LearnMoreUrl)
.filter(_.nonEmpty)
PolicyFeatureSwitchResults(limitedActionTypes, copyNamespace, promptType, learnMoreUrl)
}
}

View File

@ -1,96 +0,0 @@
package com.twitter.visibility.interfaces.tweets.enrichments
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.builder.tweets.TweetVisibilityNudgeSourceWrapper
import com.twitter.visibility.common.actions.TweetVisibilityNudgeReason.SemanticCoreMisinformationLabelReason
import com.twitter.visibility.rules.Action
import com.twitter.visibility.rules.LocalizedNudge
import com.twitter.visibility.rules.SoftIntervention
import com.twitter.visibility.rules.TweetVisibilityNudge
object TweetVisibilityNudgeEnrichment {
def apply(
result: VisibilityResult,
tweetVisibilityNudgeSourceWrapper: TweetVisibilityNudgeSourceWrapper,
languageCode: String,
countryCode: Option[String]
): VisibilityResult = {
val softIntervention = extractSoftIntervention(result.verdict, result.secondaryVerdicts)
val enrichedPrimaryVerdict = enrichAction(
result.verdict,
tweetVisibilityNudgeSourceWrapper,
softIntervention,
languageCode,
countryCode)
val enrichedSecondaryVerdicts: Seq[Action] =
result.secondaryVerdicts.map(sv =>
enrichAction(
sv,
tweetVisibilityNudgeSourceWrapper,
softIntervention,
languageCode,
countryCode))
result.copy(verdict = enrichedPrimaryVerdict, secondaryVerdicts = enrichedSecondaryVerdicts)
}
private def extractSoftIntervention(
primary: Action,
secondaries: Seq[Action]
): Option[SoftIntervention] = {
primary match {
case si: SoftIntervention => Some(si)
case _ =>
secondaries.collectFirst {
case sv: SoftIntervention => sv
}
}
}
private def enrichAction(
action: Action,
tweetVisibilityNudgeSourceWrapper: TweetVisibilityNudgeSourceWrapper,
softIntervention: Option[SoftIntervention],
languageCode: String,
countryCode: Option[String]
): Action = {
action match {
case TweetVisibilityNudge(reason, None) =>
val localizedNudge =
tweetVisibilityNudgeSourceWrapper.getLocalizedNudge(reason, languageCode, countryCode)
if (reason == SemanticCoreMisinformationLabelReason)
TweetVisibilityNudge(
reason,
enrichLocalizedMisInfoNudge(localizedNudge, softIntervention))
else
TweetVisibilityNudge(reason, localizedNudge)
case _ => action
}
}
private def enrichLocalizedMisInfoNudge(
localizedNudge: Option[LocalizedNudge],
softIntervention: Option[SoftIntervention]
): Option[LocalizedNudge] = {
softIntervention match {
case Some(si) => {
val enrichedLocalizedNudge = localizedNudge.map { ln =>
val enrichedLocalizedNudgeActions = ln.localizedNudgeActions.map { na =>
val enrichedPayload = na.nudgeActionPayload.map { payload =>
payload.copy(ctaUrl = si.detailsUrl, heading = si.warning)
}
na.copy(nudgeActionPayload = enrichedPayload)
}
ln.copy(localizedNudgeActions = enrichedLocalizedNudgeActions)
}
enrichedLocalizedNudge
}
case None => localizedNudge
}
}
}

View File

@ -1,21 +0,0 @@
scala_library(
sources = ["*.scala"],
compiler_option_sets = ["fatal_warnings"],
platform = "java8",
strict_deps = True,
tags = ["bazel-compatible"],
dependencies = [
"decider/src/main/scala",
"servo/decider/src/main/scala",
"src/thrift/com/twitter/gizmoduck:user-thrift-scala",
"stitch/stitch-core",
"strato/src/main/scala/com/twitter/strato/client",
"visibility/common/src/main/scala/com/twitter/visibility/common",
"visibility/lib/src/main/resources/config",
"visibility/lib/src/main/scala/com/twitter/visibility",
"visibility/lib/src/main/scala/com/twitter/visibility/builder/users",
"visibility/lib/src/main/scala/com/twitter/visibility/configapi/configs",
"visibility/lib/src/main/scala/com/twitter/visibility/features",
"visibility/lib/src/main/thrift/com/twitter/visibility/context:vf-context-scala",
],
)

View File

@ -1,111 +0,0 @@
package com.twitter.visibility.interfaces.users
import com.twitter.decider.Decider
import com.twitter.gizmoduck.thriftscala.User
import com.twitter.servo.decider.DeciderGateBuilder
import com.twitter.stitch.Stitch
import com.twitter.strato.client.Client
import com.twitter.visibility.VisibilityLibrary
import com.twitter.visibility.builder.users.AuthorFeatures
import com.twitter.visibility.builder.users.RelationshipFeatures
import com.twitter.visibility.builder.users.ViewerAdvancedFilteringFeatures
import com.twitter.visibility.builder.users.ViewerFeatures
import com.twitter.visibility.builder.users.ViewerSearchSafetyFeatures
import com.twitter.visibility.builder.VisibilityResult
import com.twitter.visibility.builder.users.SearchFeatures
import com.twitter.visibility.common.UserRelationshipSource
import com.twitter.visibility.common.UserSearchSafetySource
import com.twitter.visibility.common.UserSource
import com.twitter.visibility.configapi.configs.VisibilityDeciderGates
import com.twitter.visibility.context.thriftscala.UserVisibilityFilteringContext
import com.twitter.visibility.models.ContentId.UserId
import com.twitter.visibility.models.SafetyLevel
import com.twitter.visibility.models.ViewerContext
import com.twitter.visibility.rules.Reason.Unspecified
import com.twitter.visibility.rules.Allow
import com.twitter.visibility.rules.Drop
import com.twitter.visibility.rules.RuleBase
object UserVisibilityLibrary {
type Type =
(User, SafetyLevel, ViewerContext, UserVisibilityFilteringContext) => Stitch[VisibilityResult]
def apply(
visibilityLibrary: VisibilityLibrary,
userSource: UserSource = UserSource.empty,
userRelationshipSource: UserRelationshipSource = UserRelationshipSource.empty,
stratoClient: Client,
decider: Decider
): Type = {
val libraryStatsReceiver = visibilityLibrary.statsReceiver.scope("user_library")
val stratoClientStatsReceiver = visibilityLibrary.statsReceiver.scope("strato")
val visibilityDeciderGates = VisibilityDeciderGates(decider)
val vfEngineCounter = libraryStatsReceiver.counter("vf_engine_requests")
val noUserRulesCounter = libraryStatsReceiver.counter("no_user_rules_requests")
val viewerIsAuthorCounter = libraryStatsReceiver.counter("viewer_is_author_requests")
val authorFeatures = new AuthorFeatures(userSource, libraryStatsReceiver)
val viewerFeatures = new ViewerFeatures(userSource, libraryStatsReceiver)
val relationshipFeatures =
new RelationshipFeatures(userRelationshipSource, libraryStatsReceiver)
val searchFeatures = new SearchFeatures(libraryStatsReceiver)
val viewerSafeSearchFeatures = new ViewerSearchSafetyFeatures(
UserSearchSafetySource.fromStrato(stratoClient, stratoClientStatsReceiver),
libraryStatsReceiver)
val deciderGateBuilder = new DeciderGateBuilder(decider)
val advancedFilteringFeatures =
new ViewerAdvancedFilteringFeatures(userSource, libraryStatsReceiver)
(user, safetyLevel, viewerContext, userVisibilityFilteringContext) => {
val contentId = UserId(user.id)
val viewerId = viewerContext.userId
if (!RuleBase.hasUserRules(safetyLevel)) {
noUserRulesCounter.incr()
Stitch.value(VisibilityResult(contentId = contentId, verdict = Allow))
} else {
if (viewerId.contains(user.id)) {
viewerIsAuthorCounter.incr()
Stitch.value(VisibilityResult(contentId = contentId, verdict = Allow))
} else {
vfEngineCounter.incr()
val featureMap =
visibilityLibrary.featureMapBuilder(
Seq(
viewerFeatures.forViewerContext(viewerContext),
viewerSafeSearchFeatures.forViewerId(viewerId),
relationshipFeatures.forAuthor(user, viewerId),
authorFeatures.forAuthor(user),
advancedFilteringFeatures.forViewerId(viewerId),
searchFeatures.forSearchContext(userVisibilityFilteringContext.searchContext)
)
)
visibilityLibrary.runRuleEngine(
contentId,
featureMap,
viewerContext,
safetyLevel
)
}
}
}
}
def Const(shouldDrop: Boolean): Type =
(user, _, _, _) =>
Stitch.value(
VisibilityResult(
contentId = UserId(user.id),
verdict = if (shouldDrop) Drop(Unspecified) else Allow,
finished = true
)
)
}

View File

@ -1,32 +0,0 @@
scala_library(
sources = ["*.scala"],
compiler_option_sets = ["fatal_warnings"],
platform = "java8",
strict_deps = True,
tags = ["bazel-compatible"],
dependencies = [
"configapi/configapi-core",
"datatools/src/thrift/com/twitter/datatools/entityservice:entity-entities-thrift-scala",
"escherbird/src/thrift/com/twitter/escherbird/softintervention:softintervention_thrift-scala",
"featureswitches/featureswitches-core",
"finatra-internal/request/src/main/scala",
"src/thrift/com/twitter/content-health/sensitivemediasettings:sensitivemediasettings-scala",
"src/thrift/com/twitter/context:twitter-context-scala",
"src/thrift/com/twitter/escherbird:tweet-annotation-scala",
"src/thrift/com/twitter/escherbird/common:common-scala",
"src/thrift/com/twitter/gizmoduck:user-thrift-scala",
"src/thrift/com/twitter/spam/rtf:safety-level-scala",
"src/thrift/com/twitter/spam/rtf:safety-result-scala",
"src/thrift/com/twitter/spam/rtf:tweet-rtf-event-scala",
"src/thrift/com/twitter/tweetypie:tweet-scala",
"timelines/src/main/scala/com/twitter/timelines/model/candidate",
"timelines/src/main/scala/com/twitter/timelines/util/client_info",
"twitter-context/src/main/scala",
"visibility/common/src/main/scala/com/twitter/visibility/common/actions",
"visibility/common/src/main/thrift/com/twitter/visibility:action-scala",
"visibility/lib/src/main/scala/com/twitter/visibility/configapi/params",
"visibility/lib/src/main/scala/com/twitter/visibility/util",
"visibility/lib/src/main/thrift/com/twitter/visibility/safety_label_store:safety-label-store-scala",
"visibility/lib/src/main/thrift/com/twitter/visibility/strato:vf-strato-scala",
],
)

View File

@ -1,23 +0,0 @@
package com.twitter.visibility.models
import com.twitter.tweetypie.thriftscala.Communities
import com.twitter.tweetypie.thriftscala.Tweet
object CommunityTweet {
def getCommunityId(communities: Communities): Option[CommunityId] =
communities.communityIds.headOption
def getCommunityId(tweet: Tweet): Option[CommunityId] =
tweet.communities.flatMap(getCommunityId)
def apply(tweet: Tweet): Option[CommunityTweet] =
getCommunityId(tweet).map { communityId =>
val authorId = tweet.coreData.get.userId
CommunityTweet(tweet, communityId, authorId)
}
}
case class CommunityTweet(
tweet: Tweet,
communityId: CommunityId,
authorId: Long)

View File

@ -1,22 +0,0 @@
package com.twitter.visibility.models
sealed trait ContentId
object ContentId {
case class TweetId(id: Long) extends ContentId
case class UserId(id: Long) extends ContentId
case class CardId(url: String) extends ContentId
case class QuotedTweetRelationship(outer: Long, inner: Long) extends ContentId
case class NotificationId(tweetId: Option[Long]) extends ContentId
case class DmId(id: Long) extends ContentId
case class BlenderTweetId(id: Long) extends ContentId
case class SpaceId(id: String) extends ContentId
case class SpacePlusUserId(id: String) extends ContentId
case class DmConversationId(id: String) extends ContentId
case class DmEventId(id: Long) extends ContentId
case class UserUnavailableState(tweetId: Long) extends ContentId
case class TwitterArticleId(id: Long) extends ContentId
case class DeleteTweetId(tweetId: Long) extends ContentId
case class MediaId(id: String) extends ContentId
case class CommunityId(communityId: Long) extends ContentId
}

View File

@ -1,61 +0,0 @@
package com.twitter.visibility.models
import com.twitter.spam.rtf.thriftscala.SafetyResultReason
import java.util.regex.Pattern
sealed trait LabelSource {
val name: String
}
object LabelSource {
val BotRulePrefix = "bot_id_"
val AbusePrefix = "Abuse"
val HSEPrefix = "hse"
val AgentSourceNames = Set(
SafetyResultReason.OneOff.name,
SafetyResultReason.VotingMisinformation.name,
SafetyResultReason.HackedMaterials.name,
SafetyResultReason.Scams.name,
SafetyResultReason.PlatformManipulation.name
)
val Regex = "\\|"
val pattern: Pattern = Pattern.compile(Regex)
def fromString(name: String): Option[LabelSource] = Some(name) collect {
case _ if name.startsWith(BotRulePrefix) =>
BotMakerRule(name.substring(BotRulePrefix.length).toLong)
case _ if name == "A" || name == "B" || name == "AB" =>
SmyteSource(name)
case _ if name.startsWith(AbusePrefix) =>
AbuseSource(name)
case _ if name.startsWith(HSEPrefix) =>
HSESource(name)
case _ if AgentSourceNames.contains(name) =>
AgentSource(name)
case _ =>
StringSource(name)
}
def parseStringSource(source: String): (String, Option[String]) = {
pattern.split(source, 2) match {
case Array(copy, "") => (copy, None)
case Array(copy, link) => (copy, Some(link))
case Array(copy) => (copy, None)
}
}
case class BotMakerRule(ruleId: Long) extends LabelSource {
override lazy val name: String = s"${BotRulePrefix}${ruleId}"
}
case class SmyteSource(name: String) extends LabelSource
case class AbuseSource(name: String) extends LabelSource
case class AgentSource(name: String) extends LabelSource
case class HSESource(name: String) extends LabelSource
case class StringSource(name: String) extends LabelSource
}

View File

@ -1,89 +0,0 @@
package com.twitter.visibility.models
import com.twitter.visibility.safety_label_store.{thriftscala => s}
import com.twitter.visibility.util.NamingUtils
sealed trait MediaSafetyLabelType extends SafetyLabelType {
lazy val name: String = NamingUtils.getFriendlyName(this)
}
object MediaSafetyLabelType extends SafetyLabelType {
val List: List[MediaSafetyLabelType] = s.MediaSafetyLabelType.list.map(fromThrift)
val ActiveLabels: List[MediaSafetyLabelType] = List.filter { labelType =>
labelType != Unknown && labelType != Deprecated
}
private lazy val nameToValueMap: Map[String, MediaSafetyLabelType] =
List.map(l => l.name.toLowerCase -> l).toMap
def fromName(name: String): Option[MediaSafetyLabelType] = nameToValueMap.get(name.toLowerCase)
private val UnknownThriftSafetyLabelType =
s.MediaSafetyLabelType.EnumUnknownMediaSafetyLabelType(UnknownEnumValue)
private lazy val thriftToModelMap: Map[s.MediaSafetyLabelType, MediaSafetyLabelType] = Map(
s.MediaSafetyLabelType.NsfwHighPrecision -> NsfwHighPrecision,
s.MediaSafetyLabelType.NsfwHighRecall -> NsfwHighRecall,
s.MediaSafetyLabelType.NsfwNearPerfect -> NsfwNearPerfect,
s.MediaSafetyLabelType.NsfwCardImage -> NsfwCardImage,
s.MediaSafetyLabelType.Pdna -> Pdna,
s.MediaSafetyLabelType.PdnaNoTreatmentIfVerified -> PdnaNoTreatmentIfVerified,
s.MediaSafetyLabelType.DmcaWithheld -> DmcaWithheld,
s.MediaSafetyLabelType.LegalDemandsWithheld -> LegalDemandsWithheld,
s.MediaSafetyLabelType.LocalLawsWithheld -> LocalLawsWithheld,
s.MediaSafetyLabelType.Reserved10 -> Deprecated,
s.MediaSafetyLabelType.Reserved11 -> Deprecated,
s.MediaSafetyLabelType.Reserved12 -> Deprecated,
s.MediaSafetyLabelType.Reserved13 -> Deprecated,
s.MediaSafetyLabelType.Reserved14 -> Deprecated,
s.MediaSafetyLabelType.Reserved15 -> Deprecated,
s.MediaSafetyLabelType.Reserved16 -> Deprecated,
s.MediaSafetyLabelType.Reserved17 -> Deprecated,
s.MediaSafetyLabelType.Reserved18 -> Deprecated,
s.MediaSafetyLabelType.Reserved19 -> Deprecated,
s.MediaSafetyLabelType.Reserved20 -> Deprecated,
s.MediaSafetyLabelType.Reserved21 -> Deprecated,
s.MediaSafetyLabelType.Reserved22 -> Deprecated,
s.MediaSafetyLabelType.Reserved23 -> Deprecated,
s.MediaSafetyLabelType.Reserved24 -> Deprecated,
s.MediaSafetyLabelType.Reserved25 -> Deprecated,
s.MediaSafetyLabelType.Reserved26 -> Deprecated,
s.MediaSafetyLabelType.Reserved27 -> Deprecated,
)
private lazy val modelToThriftMap: Map[MediaSafetyLabelType, s.MediaSafetyLabelType] =
(for ((k, v) <- thriftToModelMap) yield (v, k)) ++ Map(
Deprecated -> s.MediaSafetyLabelType.EnumUnknownMediaSafetyLabelType(DeprecatedEnumValue),
)
case object NsfwHighPrecision extends MediaSafetyLabelType
case object NsfwHighRecall extends MediaSafetyLabelType
case object NsfwNearPerfect extends MediaSafetyLabelType
case object NsfwCardImage extends MediaSafetyLabelType
case object Pdna extends MediaSafetyLabelType
case object PdnaNoTreatmentIfVerified extends MediaSafetyLabelType
case object DmcaWithheld extends MediaSafetyLabelType
case object LegalDemandsWithheld extends MediaSafetyLabelType
case object LocalLawsWithheld extends MediaSafetyLabelType
case object Deprecated extends MediaSafetyLabelType
case object Unknown extends MediaSafetyLabelType
def fromThrift(safetyLabelType: s.MediaSafetyLabelType): MediaSafetyLabelType =
thriftToModelMap.get(safetyLabelType) match {
case Some(mediaSafetyLabelType) => mediaSafetyLabelType
case _ =>
safetyLabelType match {
case s.MediaSafetyLabelType.EnumUnknownMediaSafetyLabelType(DeprecatedEnumValue) =>
Deprecated
case _ =>
Unknown
}
}
def toThrift(safetyLabelType: MediaSafetyLabelType): s.MediaSafetyLabelType = {
modelToThriftMap
.get(safetyLabelType).getOrElse(UnknownThriftSafetyLabelType)
}
}

View File

@ -1,179 +0,0 @@
package com.twitter.visibility.models
import com.twitter.datatools.entityservice.entities.thriftscala.FleetInterstitial
import com.twitter.datatools.entityservice.entities.{thriftscala => t}
import com.twitter.escherbird.softintervention.thriftscala.MisinformationLocalizedPolicy
import com.twitter.escherbird.thriftscala.TweetEntityAnnotation
case class MisinformationPolicy(
semanticCoreAnnotation: SemanticCoreAnnotation,
priority: Long = MisinformationPolicy.DefaultPriority,
filteringLevel: Int = MisinformationPolicy.DefaultFilteringLevel,
publishedState: PublishedState = MisinformationPolicy.DefaultPublishedState,
engagementNudge: Boolean = MisinformationPolicy.DefaultEngagementNudge,
suppressAutoplay: Boolean = MisinformationPolicy.DefaultSuppressAutoplay,
warning: Option[String] = None,
detailsUrl: Option[String] = None,
displayType: Option[MisinfoPolicyDisplayType] = None,
applicableCountries: Seq[String] = Seq.empty,
fleetInterstitial: Option[FleetInterstitial] = None)
object MisinformationPolicy {
private val DefaultPriority = 0
private val DefaultFilteringLevel = 1
private val DefaultPublishedState = PublishedState.Published
private val DefaultEngagementNudge = true
private val DefaultSuppressAutoplay = true
def apply(
annotation: TweetEntityAnnotation,
misinformation: MisinformationLocalizedPolicy
): MisinformationPolicy = {
MisinformationPolicy(
semanticCoreAnnotation = SemanticCoreAnnotation(
groupId = annotation.groupId,
domainId = annotation.domainId,
entityId = annotation.entityId
),
priority = misinformation.priority.getOrElse(DefaultPriority),
filteringLevel = misinformation.filteringLevel.getOrElse(DefaultFilteringLevel),
publishedState = misinformation.publishedState match {
case Some(t.PublishedState.Draft) => PublishedState.Draft
case Some(t.PublishedState.Dogfood) => PublishedState.Dogfood
case Some(t.PublishedState.Published) => PublishedState.Published
case _ => DefaultPublishedState
},
displayType = misinformation.displayType collect {
case t.MisinformationDisplayType.GetTheLatest => MisinfoPolicyDisplayType.GetTheLatest
case t.MisinformationDisplayType.StayInformed => MisinfoPolicyDisplayType.StayInformed
case t.MisinformationDisplayType.Misleading => MisinfoPolicyDisplayType.Misleading
case t.MisinformationDisplayType.GovernmentRequested =>
MisinfoPolicyDisplayType.GovernmentRequested
},
applicableCountries = misinformation.applicableCountries match {
case Some(countries) => countries.map(countryCode => countryCode.toLowerCase)
case _ => Seq.empty
},
fleetInterstitial = misinformation.fleetInterstitial,
engagementNudge = misinformation.engagementNudge.getOrElse(DefaultEngagementNudge),
suppressAutoplay = misinformation.suppressAutoplay.getOrElse(DefaultSuppressAutoplay),
warning = misinformation.warning,
detailsUrl = misinformation.detailsUrl,
)
}
}
trait MisinformationPolicyTransform {
def apply(policies: Seq[MisinformationPolicy]): Seq[MisinformationPolicy]
def andThen(transform: MisinformationPolicyTransform): MisinformationPolicyTransform =
(policies: Seq[MisinformationPolicy]) => transform(this.apply(policies))
}
object MisinformationPolicyTransform {
def prioritize: MisinformationPolicyTransform =
(policies: Seq[MisinformationPolicy]) =>
policies
.sortBy(p => p.filteringLevel)(Ordering[Int].reverse)
.sortBy(p => p.priority)(Ordering[Long].reverse)
def filter(filters: Seq[MisinformationPolicy => Boolean]): MisinformationPolicyTransform =
(policies: Seq[MisinformationPolicy]) =>
policies.filter { policy => filters.forall { filter => filter(policy) } }
def filterLevelAndState(
filteringLevel: Int,
publishedStates: Seq[PublishedState]
): MisinformationPolicyTransform =
filter(
Seq(
hasFilteringLevelAtLeast(filteringLevel),
hasPublishedStates(publishedStates)
))
def filterLevelAndStateAndLocalized(
filteringLevel: Int,
publishedStates: Seq[PublishedState]
): MisinformationPolicyTransform =
filter(
Seq(
hasFilteringLevelAtLeast(filteringLevel),
hasPublishedStates(publishedStates),
hasNonEmptyLocalization,
))
def filterState(
publishedStates: Seq[PublishedState]
): MisinformationPolicyTransform =
filter(
Seq(
hasPublishedStates(publishedStates)
))
def filterStateAndLocalized(
publishedStates: Seq[PublishedState]
): MisinformationPolicyTransform =
filter(
Seq(
hasPublishedStates(publishedStates),
hasNonEmptyLocalization,
))
def filterApplicableCountries(
countryCode: Option[String],
): MisinformationPolicyTransform =
filter(Seq(policyAppliesToCountry(countryCode)))
def filterOutGeoSpecific(): MisinformationPolicyTransform =
filter(Seq(policyIsGlobal()))
def filterNonEngagementNudges(): MisinformationPolicyTransform =
filter(
Seq(
hasEngagementNudge,
))
def policyAppliesToCountry(countryCode: Option[String]): MisinformationPolicy => Boolean =
policy =>
policy.applicableCountries.isEmpty ||
(countryCode.nonEmpty && policy.applicableCountries.contains(countryCode.get))
def policyIsGlobal(): MisinformationPolicy => Boolean =
policy => policy.applicableCountries.isEmpty
def hasFilteringLevelAtLeast(filteringLevel: Int): MisinformationPolicy => Boolean =
_.filteringLevel >= filteringLevel
def hasPublishedStates(
publishedStates: Seq[PublishedState]
): MisinformationPolicy => Boolean =
policy => publishedStates.contains(policy.publishedState)
def hasNonEmptyLocalization: MisinformationPolicy => Boolean =
policy => policy.warning.nonEmpty && policy.detailsUrl.nonEmpty
def hasEngagementNudge: MisinformationPolicy => Boolean =
policy => policy.engagementNudge
}
sealed trait PublishedState
object PublishedState {
case object Draft extends PublishedState
case object Dogfood extends PublishedState
case object Published extends PublishedState
val PublicPublishedStates = Seq(PublishedState.Published)
val EmployeePublishedStates = Seq(PublishedState.Published, PublishedState.Dogfood)
}
sealed trait MisinfoPolicyDisplayType
object MisinfoPolicyDisplayType {
case object GetTheLatest extends MisinfoPolicyDisplayType
case object StayInformed extends MisinfoPolicyDisplayType
case object Misleading extends MisinfoPolicyDisplayType
case object GovernmentRequested extends MisinfoPolicyDisplayType
}
object SemanticCoreMisinformation {
val domainId: Long = 148L
}

View File

@ -1,3 +0,0 @@
package com.twitter.visibility.models
case class MutedKeyword(keyword: Option[String])

View File

@ -1,90 +0,0 @@
package com.twitter.visibility.models
import com.twitter.spam.rtf.{thriftscala => s}
import com.twitter.visibility.safety_label_store.{thriftscala => store}
case class SafetyLabel(
score: Option[Double] = None,
applicableUsers: Set[Long] = Set.empty,
source: Option[LabelSource] = None,
modelMetadata: Option[TweetModelMetadata] = None,
createdAtMsec: Option[Long] = None,
expiresAtMsec: Option[Long] = None,
labelMetadata: Option[SafetyLabelMetadata] = None,
applicableCountries: Option[Seq[String]] = None)
object SafetyLabel {
def fromThrift(safetyLabel: s.SafetyLabel): SafetyLabel = {
SafetyLabel(
score = safetyLabel.score,
applicableUsers = safetyLabel.applicableUsers
.map { perspectivalUsers =>
(perspectivalUsers map {
_.userId
}).toSet
}.getOrElse(Set.empty),
source = safetyLabel.source.flatMap(LabelSource.fromString),
modelMetadata = safetyLabel.modelMetadata.flatMap(TweetModelMetadata.fromThrift),
createdAtMsec = safetyLabel.createdAtMsec,
expiresAtMsec = safetyLabel.expiresAtMsec,
labelMetadata = safetyLabel.labelMetadata.map(SafetyLabelMetadata.fromThrift(_)),
applicableCountries = safetyLabel.applicableCountries
)
}
def toThrift(safetyLabel: SafetyLabel): s.SafetyLabel = {
s.SafetyLabel(
score = safetyLabel.score,
applicableUsers = if (safetyLabel.applicableUsers.nonEmpty) {
Some(safetyLabel.applicableUsers.toSeq.map {
s.PerspectivalUser(_)
})
} else {
None
},
source = safetyLabel.source.map(_.name),
modelMetadata = safetyLabel.modelMetadata.map(TweetModelMetadata.toThrift),
createdAtMsec = safetyLabel.createdAtMsec,
expiresAtMsec = safetyLabel.expiresAtMsec,
labelMetadata = safetyLabel.labelMetadata.map(_.toThrift),
applicableCountries = safetyLabel.applicableCountries
)
}
}
trait SafetyLabelWithType[EntitySafetyLabelType <: SafetyLabelType] {
val safetyLabelType: EntitySafetyLabelType
val safetyLabel: SafetyLabel
}
case class MediaSafetyLabel(
override val safetyLabelType: MediaSafetyLabelType,
override val safetyLabel: SafetyLabel)
extends SafetyLabelWithType[MediaSafetyLabelType] {
def fromThrift(
thriftType: store.MediaSafetyLabelType,
thriftLabel: s.SafetyLabel
): MediaSafetyLabel = {
MediaSafetyLabel(
MediaSafetyLabelType.fromThrift(thriftType),
SafetyLabel.fromThrift(thriftLabel)
)
}
}
case class SpaceSafetyLabel(
override val safetyLabelType: SpaceSafetyLabelType,
override val safetyLabel: SafetyLabel)
extends SafetyLabelWithType[SpaceSafetyLabelType] {
def fromThrift(
thriftType: store.SpaceSafetyLabelType,
thriftLabel: s.SafetyLabel
): SpaceSafetyLabel = {
SpaceSafetyLabel(
SpaceSafetyLabelType.fromThrift(thriftType),
SafetyLabel.fromThrift(thriftLabel)
)
}
}

View File

@ -1,25 +0,0 @@
package com.twitter.visibility.models
import com.twitter.guano.commons.thriftscala.PolicyInViolation
import com.twitter.spam.rtf.{thriftscala => s}
case class SafetyLabelMetadata(
policyInViolation: Option[PolicyInViolation] = None,
policyUrl: Option[String] = None) {
def toThrift: s.SafetyLabelMetadata = {
s.SafetyLabelMetadata(
policyInViolation,
policyUrl
)
}
}
object SafetyLabelMetadata {
def fromThrift(metadata: s.SafetyLabelMetadata): SafetyLabelMetadata = {
SafetyLabelMetadata(
metadata.policyInViolation,
metadata.policyUrl
)
}
}

View File

@ -1,7 +0,0 @@
package com.twitter.visibility.models
trait SafetyLabelType {
val DeprecatedEnumValue: Short = -1
val UnknownEnumValue: Short = -2
val StratoOnlyLabelEnumValue: Short = -3
}

View File

@ -1,855 +0,0 @@
package com.twitter.visibility.models
import com.twitter.spam.rtf.thriftscala.{SafetyLevel => ThriftSafetyLevel}
import com.twitter.visibility.configapi.params.SafetyLevelParam
import com.twitter.visibility.configapi.params.SafetyLevelParams._
sealed trait SafetyLevel {
val name: String = this.getClass.getSimpleName.dropRight(1)
def enabledParam: SafetyLevelParam
}
object SafetyLevel {
private lazy val nameToSafetyLevelMap: Map[String, SafetyLevel] =
SafetyLevel.List.map(s => s.name.toLowerCase -> s).toMap
def fromName(name: String): Option[SafetyLevel] = {
nameToSafetyLevelMap.get(name.toLowerCase)
}
private val DeprecatedEnumValue = -1
private lazy val thriftToModelMap: Map[ThriftSafetyLevel, SafetyLevel] = Map(
ThriftSafetyLevel.AccessInternalPromotedContent -> AccessInternalPromotedContent,
ThriftSafetyLevel.AdsBusinessSettings -> AdsBusinessSettings,
ThriftSafetyLevel.AdsCampaign -> AdsCampaign,
ThriftSafetyLevel.AdsManager -> AdsManager,
ThriftSafetyLevel.AdsReportingDashboard -> AdsReportingDashboard,
ThriftSafetyLevel.AllSubscribedLists -> AllSubscribedLists,
ThriftSafetyLevel.Appeals -> Appeals,
ThriftSafetyLevel.ArticleTweetTimeline -> ArticleTweetTimeline,
ThriftSafetyLevel.BaseQig -> BaseQig,
ThriftSafetyLevel.BirdwatchNoteAuthor -> BirdwatchNoteAuthor,
ThriftSafetyLevel.BirdwatchNoteTweetsTimeline -> BirdwatchNoteTweetsTimeline,
ThriftSafetyLevel.BirdwatchNeedsYourHelpNotifications -> BirdwatchNeedsYourHelpNotifications,
ThriftSafetyLevel.BlockMuteUsersTimeline -> BlockMuteUsersTimeline,
ThriftSafetyLevel.BrandSafety -> BrandSafety,
ThriftSafetyLevel.CardPollVoting -> CardPollVoting,
ThriftSafetyLevel.CardsService -> CardsService,
ThriftSafetyLevel.Communities -> Communities,
ThriftSafetyLevel.ContentControlToolInstall -> ContentControlToolInstall,
ThriftSafetyLevel.ConversationFocalPrehydration -> ConversationFocalPrehydration,
ThriftSafetyLevel.ConversationFocalTweet -> ConversationFocalTweet,
ThriftSafetyLevel.ConversationInjectedTweet -> ConversationInjectedTweet,
ThriftSafetyLevel.ConversationReply -> ConversationReply,
ThriftSafetyLevel.CuratedTrendsRepresentativeTweet -> CuratedTrendsRepresentativeTweet,
ThriftSafetyLevel.CurationPolicyViolations -> CurationPolicyViolations,
ThriftSafetyLevel.DevPlatformGetListTweets -> DevPlatformGetListTweets,
ThriftSafetyLevel.DesFollowingAndFollowersUserList -> DesFollowingAndFollowersUserList,
ThriftSafetyLevel.DesHomeTimeline -> DesHomeTimeline,
ThriftSafetyLevel.DesQuoteTweetTimeline -> DesQuoteTweetTimeline,
ThriftSafetyLevel.DesRealtime -> DesRealtime,
ThriftSafetyLevel.DesRealtimeSpamEnrichment -> DesRealtimeSpamEnrichment,
ThriftSafetyLevel.DesRealtimeTweetFilter -> DesRealtimeTweetFilter,
ThriftSafetyLevel.DesRetweetingUsers -> DesRetweetingUsers,
ThriftSafetyLevel.DesTweetDetail -> DesTweetDetail,
ThriftSafetyLevel.DesTweetLikingUsers -> DesTweetLikingUsers,
ThriftSafetyLevel.DesUserBookmarks -> DesUserBookmarks,
ThriftSafetyLevel.DesUserLikedTweets -> DesUserLikedTweets,
ThriftSafetyLevel.DesUserMentions -> DesUserMentions,
ThriftSafetyLevel.DesUserTweets -> DesUserTweets,
ThriftSafetyLevel.DevPlatformComplianceStream -> DevPlatformComplianceStream,
ThriftSafetyLevel.DirectMessages -> DirectMessages,
ThriftSafetyLevel.DirectMessagesConversationList -> DirectMessagesConversationList,
ThriftSafetyLevel.DirectMessagesConversationTimeline -> DirectMessagesConversationTimeline,
ThriftSafetyLevel.DirectMessagesInbox -> DirectMessagesInbox,
ThriftSafetyLevel.DirectMessagesMutedUsers -> DirectMessagesMutedUsers,
ThriftSafetyLevel.DirectMessagesPinned -> DirectMessagesPinned,
ThriftSafetyLevel.DirectMessagesSearch -> DirectMessagesSearch,
ThriftSafetyLevel.EditHistoryTimeline -> EditHistoryTimeline,
ThriftSafetyLevel.ElevatedQuoteTweetTimeline -> ElevatedQuoteTweetTimeline,
ThriftSafetyLevel.EmbeddedTweet -> EmbeddedTweet,
ThriftSafetyLevel.EmbedsPublicInterestNotice -> EmbedsPublicInterestNotice,
ThriftSafetyLevel.EmbedTweetMarkup -> EmbedTweetMarkup,
ThriftSafetyLevel.ExploreRecommendations -> ExploreRecommendations,
ThriftSafetyLevel.WritePathLimitedActionsEnforcement -> WritePathLimitedActionsEnforcement,
ThriftSafetyLevel.FilterAll -> FilterAll,
ThriftSafetyLevel.FilterAllPlaceholder -> FilterAllPlaceholder,
ThriftSafetyLevel.FilterDefault -> FilterDefault,
ThriftSafetyLevel.FilterNone -> FilterNone,
ThriftSafetyLevel.FollowedTopicsTimeline -> FollowedTopicsTimeline,
ThriftSafetyLevel.FollowerConnections -> FollowerConnections,
ThriftSafetyLevel.FollowingAndFollowersUserList -> FollowingAndFollowersUserList,
ThriftSafetyLevel.ForDevelopmentOnly -> ForDevelopmentOnly,
ThriftSafetyLevel.FriendsFollowingList -> FriendsFollowingList,
ThriftSafetyLevel.GraphqlDefault -> GraphqlDefault,
ThriftSafetyLevel.HumanizationNudge -> HumanizationNudge,
ThriftSafetyLevel.KitchenSinkDevelopment -> KitchenSinkDevelopment,
ThriftSafetyLevel.ListHeader -> ListHeader,
ThriftSafetyLevel.ListMemberships -> ListMemberships,
ThriftSafetyLevel.ListOwnerships -> ListOwnerships,
ThriftSafetyLevel.ListRecommendations -> ListRecommendations,
ThriftSafetyLevel.ListSearch -> ListSearch,
ThriftSafetyLevel.ListSubscriptions -> ListSubscriptions,
ThriftSafetyLevel.LivePipelineEngagementCounts -> LivePipelineEngagementCounts,
ThriftSafetyLevel.LiveVideoTimeline -> LiveVideoTimeline,
ThriftSafetyLevel.MagicRecs -> MagicRecs,
ThriftSafetyLevel.MagicRecsV2 -> MagicRecsV2,
ThriftSafetyLevel.MagicRecsAggressive -> MagicRecsAggressive,
ThriftSafetyLevel.MagicRecsAggressiveV2 -> MagicRecsAggressiveV2,
ThriftSafetyLevel.Minimal -> Minimal,
ThriftSafetyLevel.ModeratedTweetsTimeline -> ModeratedTweetsTimeline,
ThriftSafetyLevel.Moments -> Moments,
ThriftSafetyLevel.NearbyTimeline -> NearbyTimeline,
ThriftSafetyLevel.NewUserExperience -> NewUserExperience,
ThriftSafetyLevel.NotificationsIbis -> NotificationsIbis,
ThriftSafetyLevel.NotificationsPlatform -> NotificationsPlatform,
ThriftSafetyLevel.NotificationsPlatformPush -> NotificationsPlatformPush,
ThriftSafetyLevel.NotificationsQig -> NotificationsQig,
ThriftSafetyLevel.NotificationsRead -> NotificationsRead,
ThriftSafetyLevel.NotificationsTimelineDeviceFollow -> NotificationsTimelineDeviceFollow,
ThriftSafetyLevel.NotificationsWrite -> NotificationsWrite,
ThriftSafetyLevel.NotificationsWriterTweetHydrator -> NotificationsWriterTweetHydrator,
ThriftSafetyLevel.NotificationsWriterV2 -> NotificationsWriterV2,
ThriftSafetyLevel.ProfileMixerMedia -> ProfileMixerMedia,
ThriftSafetyLevel.ProfileMixerFavorites -> ProfileMixerFavorites,
ThriftSafetyLevel.QuickPromoteTweetEligibility -> QuickPromoteTweetEligibility,
ThriftSafetyLevel.QuoteTweetTimeline -> QuoteTweetTimeline,
ThriftSafetyLevel.QuotedTweetRules -> QuotedTweetRules,
ThriftSafetyLevel.Recommendations -> Recommendations,
ThriftSafetyLevel.RecosVideo -> RecosVideo,
ThriftSafetyLevel.RecosWritePath -> RecosWritePath,
ThriftSafetyLevel.RepliesGrouping -> RepliesGrouping,
ThriftSafetyLevel.ReportCenter -> ReportCenter,
ThriftSafetyLevel.ReturningUserExperience -> ReturningUserExperience,
ThriftSafetyLevel.ReturningUserExperienceFocalTweet -> ReturningUserExperienceFocalTweet,
ThriftSafetyLevel.Revenue -> Revenue,
ThriftSafetyLevel.RitoActionedTweetTimeline -> RitoActionedTweetTimeline,
ThriftSafetyLevel.SafeSearchMinimal -> SafeSearchMinimal,
ThriftSafetyLevel.SafeSearchStrict -> SafeSearchStrict,
ThriftSafetyLevel.SearchHydration -> SearchHydration,
ThriftSafetyLevel.SearchLatest -> SearchLatest,
ThriftSafetyLevel.SearchTop -> SearchTop,
ThriftSafetyLevel.SearchTopQig -> SearchTopQig,
ThriftSafetyLevel.SearchMixerSrpMinimal -> SearchMixerSrpMinimal,
ThriftSafetyLevel.SearchMixerSrpStrict -> SearchMixerSrpStrict,
ThriftSafetyLevel.SearchPeopleSrp -> SearchPeopleSrp,
ThriftSafetyLevel.SearchPeopleTypeahead -> SearchPeopleTypeahead,
ThriftSafetyLevel.SearchPhoto -> SearchPhoto,
ThriftSafetyLevel.SearchTrendTakeoverPromotedTweet -> SearchTrendTakeoverPromotedTweet,
ThriftSafetyLevel.SearchVideo -> SearchVideo,
ThriftSafetyLevel.SearchBlenderUserRules -> SearchBlenderUserRules,
ThriftSafetyLevel.SearchLatestUserRules -> SearchLatestUserRules,
ThriftSafetyLevel.ShoppingManagerSpyMode -> ShoppingManagerSpyMode,
ThriftSafetyLevel.SignalsReactions -> SignalsReactions,
ThriftSafetyLevel.SignalsTweetReactingUsers -> SignalsTweetReactingUsers,
ThriftSafetyLevel.SocialProof -> SocialProof,
ThriftSafetyLevel.SoftInterventionPivot -> SoftInterventionPivot,
ThriftSafetyLevel.SpaceFleetline -> SpaceFleetline,
ThriftSafetyLevel.SpaceHomeTimelineUpranking -> SpaceHomeTimelineUpranking,
ThriftSafetyLevel.SpaceJoinScreen -> SpaceJoinScreen,
ThriftSafetyLevel.SpaceNotifications -> SpaceNotifications,
ThriftSafetyLevel.Spaces -> Spaces,
ThriftSafetyLevel.SpacesParticipants -> SpacesParticipants,
ThriftSafetyLevel.SpacesSellerApplicationStatus -> SpacesSellerApplicationStatus,
ThriftSafetyLevel.SpacesSharing -> SpacesSharing,
ThriftSafetyLevel.SpaceTweetAvatarHomeTimeline -> SpaceTweetAvatarHomeTimeline,
ThriftSafetyLevel.StickersTimeline -> StickersTimeline,
ThriftSafetyLevel.StratoExtLimitedEngagements -> StratoExtLimitedEngagements,
ThriftSafetyLevel.StreamServices -> StreamServices,
ThriftSafetyLevel.SuperFollowerConnections -> SuperFollowerConnections,
ThriftSafetyLevel.SuperLike -> SuperLike,
ThriftSafetyLevel.Test -> Test,
ThriftSafetyLevel.TimelineBookmark -> TimelineBookmark,
ThriftSafetyLevel.TimelineContentControls -> TimelineContentControls,
ThriftSafetyLevel.TimelineConversations -> TimelineConversations,
ThriftSafetyLevel.TimelineConversationsDownranking -> TimelineConversationsDownranking,
ThriftSafetyLevel.TimelineConversationsDownrankingMinimal -> TimelineConversationsDownrankingMinimal,
ThriftSafetyLevel.TimelineFavorites -> TimelineFavorites,
ThriftSafetyLevel.TimelineFavoritesSelfView -> TimelineFavoritesSelfView,
ThriftSafetyLevel.TimelineFocalTweet -> TimelineFocalTweet,
ThriftSafetyLevel.TimelineFollowingActivity -> TimelineFollowingActivity,
ThriftSafetyLevel.TimelineHome -> TimelineHome,
ThriftSafetyLevel.TimelineHomeCommunities -> TimelineHomeCommunities,
ThriftSafetyLevel.TimelineHomeHydration -> TimelineHomeHydration,
ThriftSafetyLevel.TimelineHomeLatest -> TimelineHomeLatest,
ThriftSafetyLevel.TimelineHomePromotedHydration -> TimelineHomePromotedHydration,
ThriftSafetyLevel.TimelineHomeRecommendations -> TimelineHomeRecommendations,
ThriftSafetyLevel.TimelineHomeTopicFollowRecommendations -> TimelineHomeTopicFollowRecommendations,
ThriftSafetyLevel.TimelineScorer -> TimelineScorer,
ThriftSafetyLevel.TimelineInjection -> TimelineInjection,
ThriftSafetyLevel.TimelineLikedBy -> TimelineLikedBy,
ThriftSafetyLevel.TimelineLists -> TimelineLists,
ThriftSafetyLevel.TimelineMedia -> TimelineMedia,
ThriftSafetyLevel.TimelineMentions -> TimelineMentions,
ThriftSafetyLevel.TimelineModeratedTweetsHydration -> TimelineModeratedTweetsHydration,
ThriftSafetyLevel.TimelineProfile -> TimelineProfile,
ThriftSafetyLevel.TimelineProfileAll -> TimelineProfileAll,
ThriftSafetyLevel.TimelineProfileSpaces -> TimelineProfileSpaces,
ThriftSafetyLevel.TimelineProfileSuperFollows -> TimelineProfileSuperFollows,
ThriftSafetyLevel.TimelineReactiveBlending -> TimelineReactiveBlending,
ThriftSafetyLevel.TimelineRetweetedBy -> TimelineRetweetedBy,
ThriftSafetyLevel.TimelineSuperLikedBy -> TimelineSuperLikedBy,
ThriftSafetyLevel.Tombstoning -> Tombstoning,
ThriftSafetyLevel.TopicRecommendations -> TopicRecommendations,
ThriftSafetyLevel.TopicsLandingPageTopicRecommendations -> TopicsLandingPageTopicRecommendations,
ThriftSafetyLevel.TrendsRepresentativeTweet -> TrendsRepresentativeTweet,
ThriftSafetyLevel.TrustedFriendsUserList -> TrustedFriendsUserList,
ThriftSafetyLevel.TwitterDelegateUserList -> TwitterDelegateUserList,
ThriftSafetyLevel.GryphonDecksAndColumns -> GryphonDecksAndColumns,
ThriftSafetyLevel.TweetDetail -> TweetDetail,
ThriftSafetyLevel.TweetDetailNonToo -> TweetDetailNonToo,
ThriftSafetyLevel.TweetDetailWithInjectionsHydration -> TweetDetailWithInjectionsHydration,
ThriftSafetyLevel.TweetEngagers -> TweetEngagers,
ThriftSafetyLevel.TweetReplyNudge -> TweetReplyNudge,
ThriftSafetyLevel.TweetScopedTimeline -> TweetScopedTimeline,
ThriftSafetyLevel.TweetWritesApi -> TweetWritesApi,
ThriftSafetyLevel.TwitterArticleCompose -> TwitterArticleCompose,
ThriftSafetyLevel.TwitterArticleProfileTab -> TwitterArticleProfileTab,
ThriftSafetyLevel.TwitterArticleRead -> TwitterArticleRead,
ThriftSafetyLevel.UserProfileHeader -> UserProfileHeader,
ThriftSafetyLevel.UserMilestoneRecommendation -> UserMilestoneRecommendation,
ThriftSafetyLevel.UserScopedTimeline -> UserScopedTimeline,
ThriftSafetyLevel.UserSearchSrp -> UserSearchSrp,
ThriftSafetyLevel.UserSearchTypeahead -> UserSearchTypeahead,
ThriftSafetyLevel.UserSelfViewOnly -> UserSelfViewOnly,
ThriftSafetyLevel.UserSettings -> UserSettings,
ThriftSafetyLevel.VideoAds -> VideoAds,
ThriftSafetyLevel.ZipbirdConsumerArchives -> ZipbirdConsumerArchives,
ThriftSafetyLevel.TweetAward -> TweetAward,
)
private lazy val modelToThriftMap: Map[SafetyLevel, ThriftSafetyLevel] =
for ((k, v) <- thriftToModelMap) yield (v, k)
case object AdsBusinessSettings extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableAdsBusinessSettingsSafetyLevelParam
}
case object AdsCampaign extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableAdsCampaignSafetyLevelParam
}
case object AdsManager extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableAdsManagerSafetyLevelParam
}
case object AdsReportingDashboard extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableAdsReportingDashboardSafetyLevelParam
}
case object AllSubscribedLists extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableAllSubscribedListsSafetyLevelParam
}
case object Appeals extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableAppealsSafetyLevelParam
}
case object ArticleTweetTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableArticleTweetTimelineSafetyLevelParam
}
case object BaseQig extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableBaseQigSafetyLevelParam
}
case object BirdwatchNoteAuthor extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableBirdwatchNoteAuthorSafetyLevel
}
case object BirdwatchNoteTweetsTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableBirdwatchNoteTweetsTimelineSafetyLevel
}
case object BirdwatchNeedsYourHelpNotifications extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableBirdwatchNeedsYourHelpNotificationsSafetyLevel
}
case object BlockMuteUsersTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableBlockMuteUsersTimelineSafetyLevelParam
}
case object BrandSafety extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableBrandSafetySafetyLevelParam
}
case object CardPollVoting extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableCardPollVotingSafetyLevelParam
}
case object CardsService extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableCardsServiceSafetyLevelParam
}
case object Communities extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableCommunitiesSafetyLevelParam
}
case object ContentControlToolInstall extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableContentControlToolInstallSafetyLevelParam
}
case object ConversationFocalPrehydration extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableConversationFocalPrehydrationSafetyLevelParam
}
case object ConversationFocalTweet extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableConversationFocalTweetSafetyLevelParam
}
case object ConversationInjectedTweet extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableConversationInjectedTweetSafetyLevelParam
}
case object ConversationReply extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableConversationReplySafetyLevelParam
}
case object AccessInternalPromotedContent extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableAccessInternalPromotedContentSafetyLevelParam
}
case object CuratedTrendsRepresentativeTweet extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableCuratedTrendsRepresentativeTweet
}
case object CurationPolicyViolations extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableCurationPolicyViolations
}
case object DevPlatformGetListTweets extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDevPlatformGetListTweetsSafetyLevelParam
}
case object DesFollowingAndFollowersUserList extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableDESFollowingAndFollowersUserListSafetyLevelParam
}
case object DesHomeTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDESHomeTimelineSafetyLevelParam
}
case object DesQuoteTweetTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDESQuoteTweetTimelineSafetyLevelParam
}
case object DesRealtime extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDESRealtimeSafetyLevelParam
}
case object DesRealtimeSpamEnrichment extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDESRealtimeSpamEnrichmentSafetyLevelParam
}
case object DesRealtimeTweetFilter extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDESRealtimeTweetFilterSafetyLevelParam
}
case object DesRetweetingUsers extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDESRetweetingUsersSafetyLevelParam
}
case object DesTweetDetail extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDesTweetDetailSafetyLevelParam
}
case object DesTweetLikingUsers extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDESTweetLikingUsersSafetyLevelParam
}
case object DesUserBookmarks extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDESUserBookmarksSafetyLevelParam
}
case object DesUserLikedTweets extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDESUserLikedTweetSafetyLevelParam
}
case object DesUserMentions extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDESUserMentionsSafetyLevelParam
}
case object DesUserTweets extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDESUserTweetsSafetyLevelParam
}
case object DevPlatformComplianceStream extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDevPlatformComplianceStreamSafetyLevelParam
}
case object DirectMessages extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDirectMessagesSafetyLevelParam
}
case object DirectMessagesConversationList extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableDirectMessagesConversationListSafetyLevelParam
}
case object DirectMessagesConversationTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableDirectMessagesConversationTimelineSafetyLevelParam
}
case object DirectMessagesInbox extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableDirectMessagesInboxSafetyLevelParam
}
case object DirectMessagesMutedUsers extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDirectMessagesMutedUsersSafetyLevelParam
}
case object DirectMessagesPinned extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDirectMessagesPinnedSafetyLevelParam
}
case object DirectMessagesSearch extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDirectMessagesSearchSafetyLevelParam
}
case object EditHistoryTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableEditHistoryTimelineSafetyLevelParam
}
case object ElevatedQuoteTweetTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableElevatedQuoteTweetTimelineSafetyLevelParam
}
case object EmbeddedTweet extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableEmbeddedTweetSafetyLevelParam
}
case object EmbedsPublicInterestNotice extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableEmbedsPublicInterestNoticeSafetyLevelParam
}
case object EmbedTweetMarkup extends SafetyLevel {
override def enabledParam: SafetyLevelParam = EnableEmbedTweetMarkupSafetyLevelParam
}
case object WritePathLimitedActionsEnforcement extends SafetyLevel {
override def enabledParam: SafetyLevelParam =
EnableWritePathLimitedActionsEnforcementSafetyLevelParam
}
case object FilterNone extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableFilterNoneSafetyLevelParam
}
case object FilterAll extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableFilterAllSafetyLevelParam
}
case object FilterAllPlaceholder extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableFilterDefaultSafetyLevelParam
}
case object FilterDefault extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableFilterDefaultSafetyLevelParam
}
case object FollowedTopicsTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableFollowedTopicsTimelineSafetyLevelParam
}
case object FollowerConnections extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableFollowerConnectionsSafetyLevelParam
}
case object FollowingAndFollowersUserList extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableFollowingAndFollowersUserListSafetyLevelParam
}
case object ForDevelopmentOnly extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableForDevelopmentOnlySafetyLevelParam
}
case object FriendsFollowingList extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableFriendsFollowingListSafetyLevelParam
}
case object GraphqlDefault extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableGraphqlDefaultSafetyLevelParam
}
case object GryphonDecksAndColumns extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableGryphonDecksAndColumnsSafetyLevelParam
}
case object HumanizationNudge extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableHumanizationNudgeSafetyLevelParam
}
case object KitchenSinkDevelopment extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableKitchenSinkDevelopmentSafetyLevelParam
}
case object ListHeader extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableListHeaderSafetyLevelParam
}
case object ListMemberships extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableListMembershipsSafetyLevelParam
}
case object ListOwnerships extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableListOwnershipsSafetyLevelParam
}
case object ListRecommendations extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableListRecommendationsSafetyLevelParam
}
case object ListSearch extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableListSearchSafetyLevelParam
}
case object ListSubscriptions extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableListSubscriptionsSafetyLevelParam
}
case object LivePipelineEngagementCounts extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableLivePipelineEngagementCountsSafetyLevelParam
}
case object LiveVideoTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableLiveVideoTimelineSafetyLevelParam
}
case object MagicRecs extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableMagicRecsSafetyLevelParam
}
case object MagicRecsAggressive extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableMagicRecsAggressiveSafetyLevelParam
}
case object MagicRecsAggressiveV2 extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableMagicRecsAggressiveV2SafetyLevelParam
}
case object MagicRecsV2 extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableMagicRecsV2SafetyLevelParam
}
case object Minimal extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableMinimalSafetyLevelParam
}
case object ModeratedTweetsTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableModeratedTweetsTimelineSafetyLevelParam
}
case object Moments extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableMomentsSafetyLevelParam
}
case object NearbyTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableNearbySafetyLevelParam
}
case object NewUserExperience extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableNewUserExperienceSafetyLevelParam
}
case object NotificationsIbis extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableNotificationsIbisSafetyLevelParam
}
case object NotificationsPlatform extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableNotificationsPlatformSafetyLevelParam
}
case object NotificationsPlatformPush extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableNotificationsPlatformPushSafetyLevelParam
}
case object NotificationsQig extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableNotificationsQigSafetyLevelParam
}
case object NotificationsRead extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableNotificationsReadSafetyLevelParam
}
case object NotificationsTimelineDeviceFollow extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableNotificationsTimelineDeviceFollowSafetyLevelParam
}
case object NotificationsWrite extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableNotificationsWriteSafetyLevelParam
}
case object NotificationsWriterV2 extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableNotificationsWriterV2SafetyLevelParam
}
case object NotificationsWriterTweetHydrator extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableNotificationsWriterTweetHydratorSafetyLevelParam
}
case object ProfileMixerMedia extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableProfileMixerMediaSafetyLevelParam
}
case object ProfileMixerFavorites extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableProfileMixerFavoritesSafetyLevelParam
}
case object QuickPromoteTweetEligibility extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableQuickPromoteTweetEligibilitySafetyLevelParam
}
case object QuoteTweetTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableQuoteTweetTimelineSafetyLevelParam
}
case object QuotedTweetRules extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableQuotedTweetRulesParam
}
case object Recommendations extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableRecommendationsSafetyLevelParam
}
case object RecosVideo extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableRecosVideoSafetyLevelParam
}
case object RecosWritePath extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableRecosWritePathSafetyLevelParam
}
case object RepliesGrouping extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableRepliesGroupingSafetyLevelParam
}
case object ReportCenter extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableReportCenterSafetyLevelParam
}
case object ReturningUserExperience extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableReturningUserExperienceSafetyLevelParam
}
case object ReturningUserExperienceFocalTweet extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableReturningUserExperienceFocalTweetSafetyLevelParam
}
case object Revenue extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableRevenueSafetyLevelParam
}
case object RitoActionedTweetTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableRitoActionedTweetTimelineParam
}
case object SafeSearchMinimal extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSafeSearchMinimalSafetyLevelParam
}
case object SafeSearchStrict extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSafeSearchStrictSafetyLevelParam
}
case object SearchHydration extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchHydrationSafetyLevelParam
}
case object SearchLatest extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchLatestSafetyLevelParam
}
case object SearchMixerSrpMinimal extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchMixerSrpMinimalSafetyLevelParam
}
case object SearchMixerSrpStrict extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchMixerSrpStrictSafetyLevelParam
}
case object SearchPeopleSrp extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchPeopleSearchResultPageSafetyLevelParam
}
case object SearchPeopleTypeahead extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchPeopleTypeaheadSafetyLevelParam
}
case object SearchPhoto extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchPhotoSafetyLevelParam
}
case object ShoppingManagerSpyMode extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableShoppingManagerSpyModeSafetyLevelParam
}
case object StratoExtLimitedEngagements extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableStratoExtLimitedEngagementsSafetyLevelParam
}
case object SearchTop extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchTopSafetyLevelParam
}
case object SearchTopQig extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchTopQigSafetyLevelParam
}
case object SearchTrendTakeoverPromotedTweet extends SafetyLevel {
override val enabledParam: SafetyLevelParam = SearchTrendTakeoverPromotedTweetSafetyLevelParam
}
case object SearchVideo extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchVideoSafetyLevelParam
}
case object SearchBlenderUserRules extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchBlenderUserRulesSafetyLevelParam
}
case object SearchLatestUserRules extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSearchLatestUserRulesSafetyLevelParam
}
case object SignalsReactions extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSignalsReactionsSafetyLevelParam
}
case object SignalsTweetReactingUsers extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSignalsTweetReactingUsersSafetyLevelParam
}
case object SocialProof extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSocialProofSafetyLevelParam
}
case object SoftInterventionPivot extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSoftInterventionPivotSafetyLevelParam
}
case object SpaceFleetline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSpaceFleetlineSafetyLevelParam
}
case object SpaceHomeTimelineUpranking extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSpaceHomeTimelineUprankingSafetyLevelParam
}
case object SpaceJoinScreen extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSpaceJoinScreenSafetyLevelParam
}
case object SpaceNotifications extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSpaceNotificationSafetyLevelParam
}
case object Spaces extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSpacesSafetyLevelParam
}
case object SpacesParticipants extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSpacesParticipantsSafetyLevelParam
}
case object SpacesSellerApplicationStatus extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableSpacesSellerApplicationStatusSafetyLevelParam
}
case object SpacesSharing extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSpacesSharingSafetyLevelParam
}
case object SpaceTweetAvatarHomeTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSpaceTweetAvatarHomeTimelineSafetyLevelParam
}
case object StickersTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableStickersTimelineSafetyLevelParam
}
case object StreamServices extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableStreamServicesSafetyLevelParam
}
case object SuperFollowerConnections extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSuperFollowerConnectionsSafetyLevelParam
}
case object SuperLike extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableSuperLikeSafetyLevelParam
}
case object Test extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTestSafetyLevelParam
}
case object TimelineConversations extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineConversationsSafetyLevelParam
}
case object TimelineConversationsDownranking extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableTimelineConversationsDownrankingSafetyLevelParam
}
case object TimelineConversationsDownrankingMinimal extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableTimelineConversationsDownrankingMinimalSafetyLevelParam
}
case object TimelineFollowingActivity extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineFollowingActivitySafetyLevelParam
}
case object TimelineHome extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineHomeSafetyLevelParam
}
case object TimelineHomeCommunities extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineHomeCommunitiesSafetyLevelParam
}
case object TimelineHomeHydration extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineHomeHydrationSafetyLevelParam
}
case object TimelineHomePromotedHydration extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableTimelineHomePromotedHydrationSafetyLevelParam
}
case object TimelineHomeRecommendations extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineHomeRecommendationsSafetyLevelParam
}
case object TimelineHomeTopicFollowRecommendations extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableTimelineHomeTopicFollowRecommendationsSafetyLevelParam
}
case object TimelineScorer extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableTimelineScorerSafetyLevelParam
}
case object TopicsLandingPageTopicRecommendations extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableTopicsLandingPageTopicRecommendationsSafetyLevelParam
}
case object ExploreRecommendations extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableExploreRecommendationsSafetyLevelParam
}
case object TimelineModeratedTweetsHydration extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableTimelineModeratedTweetsHydrationSafetyLevelParam
}
case object TimelineInjection extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineInjectionSafetyLevelParam
}
case object TimelineMentions extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineMentionsSafetyLevelParam
}
case object TimelineHomeLatest extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineHomeLatestSafetyLevelParam
}
case object TimelineLikedBy extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineLikedBySafetyLevelParam
}
case object TimelineRetweetedBy extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineRetweetedBySafetyLevelParam
}
case object TimelineSuperLikedBy extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineLikedBySafetyLevelParam
}
case object TimelineBookmark extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineBookmarkSafetyLevelParam
}
case object TimelineContentControls extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineContentControlsSafetyLevelParam
}
case object TimelineMedia extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineMediaSafetyLevelParam
}
case object TimelineReactiveBlending extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineReactiveBlendingSafetyLevelParam
}
case object TimelineFavorites extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineFavoritesSafetyLevelParam
}
case object TimelineFavoritesSelfView extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineFavoritesSelfViewSafetyLevelParam
}
case object TimelineLists extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineListsSafetyLevelParam
}
case object TimelineProfile extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineProfileSafetyLevelParam
}
case object TimelineProfileAll extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineProfileAllSafetyLevelParam
}
case object TimelineProfileSpaces extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineProfileSpacesSafetyLevelParam
}
case object TimelineProfileSuperFollows extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineProfileSuperFollowsSafetyLevelParam
}
case object TimelineFocalTweet extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTimelineFocalTweetSafetyLevelParam
}
case object Tombstoning extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTombstoningSafetyLevelParam
}
case object TopicRecommendations extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTopicRecommendationsSafetyLevelParam
}
case object TrendsRepresentativeTweet extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTrendsRepresentativeTweetSafetyLevelParam
}
case object TrustedFriendsUserList extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTrustedFriendsUserListSafetyLevelParam
}
case object TwitterDelegateUserList extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTwitterDelegateUserListSafetyLevelParam
}
case object TweetDetail extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTweetDetailSafetyLevelParam
}
case object TweetDetailNonToo extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTweetDetailNonTooSafetyLevelParam
}
case object TweetDetailWithInjectionsHydration extends SafetyLevel {
override val enabledParam: SafetyLevelParam =
EnableTweetDetailWithInjectionsHydrationSafetyLevelParam
}
case object TweetEngagers extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTweetEngagersSafetyLevelParam
}
case object TweetReplyNudge extends SafetyLevel {
override def enabledParam: SafetyLevelParam = EnableTweetReplyNudgeParam
}
case object TweetScopedTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTweetScopedTimelineSafetyLevelParam
}
case object TweetWritesApi extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTweetWritesApiSafetyLevelParam
}
case object TwitterArticleCompose extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTwitterArticleComposeSafetyLevelParam
}
case object TwitterArticleProfileTab extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTwitterArticleProfileTabSafetyLevelParam
}
case object TwitterArticleRead extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTwitterArticleReadSafetyLevelParam
}
case object UserProfileHeader extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableUserProfileHeaderSafetyLevelParam
}
case object UserMilestoneRecommendation extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableUserMilestoneRecommendationSafetyLevelParam
}
case object UserScopedTimeline extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableUserScopedTimelineSafetyLevelParam
}
case object UserSearchSrp extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableUserSearchSrpSafetyLevelParam
}
case object UserSearchTypeahead extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableUserSearchTypeaheadSafetyLevelParam
}
case object UserSelfViewOnly extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableUserSelfViewOnlySafetyLevelParam
}
case object UserSettings extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableUserSettingsSafetyLevelParam
}
case object VideoAds extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableVideoAdsSafetyLevelParam
}
case object ZipbirdConsumerArchives extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableZipbirdConsumerArchivesSafetyLevelParam
}
case object TweetAward extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableTweetAwardSafetyLevelParam
}
case object DeprecatedSafetyLevel extends SafetyLevel {
override val enabledParam: SafetyLevelParam = EnableDeprecatedSafetyLevel
}
def fromThrift(safetyLevel: ThriftSafetyLevel): SafetyLevel =
thriftToModelMap.get(safetyLevel).getOrElse(DeprecatedSafetyLevel)
def toThrift(safetyLevel: SafetyLevel): ThriftSafetyLevel =
modelToThriftMap
.get(safetyLevel).getOrElse(ThriftSafetyLevel.EnumUnknownSafetyLevel(DeprecatedEnumValue))
val List: Seq[SafetyLevel] =
ThriftSafetyLevel.list.map(fromThrift).filter(_ != DeprecatedSafetyLevel)
}

View File

@ -1,554 +0,0 @@
package com.twitter.visibility.models
import com.twitter.visibility.models.SafetyLevel.AccessInternalPromotedContent
import com.twitter.visibility.models.SafetyLevel.AdsBusinessSettings
import com.twitter.visibility.models.SafetyLevel.AdsCampaign
import com.twitter.visibility.models.SafetyLevel.AdsManager
import com.twitter.visibility.models.SafetyLevel.AdsReportingDashboard
import com.twitter.visibility.models.SafetyLevel.AllSubscribedLists
import com.twitter.visibility.models.SafetyLevel.Appeals
import com.twitter.visibility.models.SafetyLevel.ArticleTweetTimeline
import com.twitter.visibility.models.SafetyLevel.BaseQig
import com.twitter.visibility.models.SafetyLevel.BirdwatchNeedsYourHelpNotifications
import com.twitter.visibility.models.SafetyLevel.BirdwatchNoteAuthor
import com.twitter.visibility.models.SafetyLevel.BirdwatchNoteTweetsTimeline
import com.twitter.visibility.models.SafetyLevel.BlockMuteUsersTimeline
import com.twitter.visibility.models.SafetyLevel.BrandSafety
import com.twitter.visibility.models.SafetyLevel.CardPollVoting
import com.twitter.visibility.models.SafetyLevel.CardsService
import com.twitter.visibility.models.SafetyLevel.ContentControlToolInstall
import com.twitter.visibility.models.SafetyLevel.ConversationFocalPrehydration
import com.twitter.visibility.models.SafetyLevel.ConversationFocalTweet
import com.twitter.visibility.models.SafetyLevel.ConversationInjectedTweet
import com.twitter.visibility.models.SafetyLevel.ConversationReply
import com.twitter.visibility.models.SafetyLevel.CuratedTrendsRepresentativeTweet
import com.twitter.visibility.models.SafetyLevel.CurationPolicyViolations
import com.twitter.visibility.models.SafetyLevel.DesFollowingAndFollowersUserList
import com.twitter.visibility.models.SafetyLevel.DesHomeTimeline
import com.twitter.visibility.models.SafetyLevel.DesQuoteTweetTimeline
import com.twitter.visibility.models.SafetyLevel.DesRealtime
import com.twitter.visibility.models.SafetyLevel.DesRealtimeSpamEnrichment
import com.twitter.visibility.models.SafetyLevel.DesRealtimeTweetFilter
import com.twitter.visibility.models.SafetyLevel.DesRetweetingUsers
import com.twitter.visibility.models.SafetyLevel.DesTweetDetail
import com.twitter.visibility.models.SafetyLevel.DesTweetLikingUsers
import com.twitter.visibility.models.SafetyLevel.DesUserBookmarks
import com.twitter.visibility.models.SafetyLevel.DesUserLikedTweets
import com.twitter.visibility.models.SafetyLevel.DesUserMentions
import com.twitter.visibility.models.SafetyLevel.DesUserTweets
import com.twitter.visibility.models.SafetyLevel.DevPlatformComplianceStream
import com.twitter.visibility.models.SafetyLevel.DevPlatformGetListTweets
import com.twitter.visibility.models.SafetyLevel.DirectMessages
import com.twitter.visibility.models.SafetyLevel.DirectMessagesConversationList
import com.twitter.visibility.models.SafetyLevel.DirectMessagesConversationTimeline
import com.twitter.visibility.models.SafetyLevel.DirectMessagesInbox
import com.twitter.visibility.models.SafetyLevel.DirectMessagesMutedUsers
import com.twitter.visibility.models.SafetyLevel.DirectMessagesPinned
import com.twitter.visibility.models.SafetyLevel.DirectMessagesSearch
import com.twitter.visibility.models.SafetyLevel.EditHistoryTimeline
import com.twitter.visibility.models.SafetyLevel.ElevatedQuoteTweetTimeline
import com.twitter.visibility.models.SafetyLevel.EmbedTweetMarkup
import com.twitter.visibility.models.SafetyLevel.EmbeddedTweet
import com.twitter.visibility.models.SafetyLevel.EmbedsPublicInterestNotice
import com.twitter.visibility.models.SafetyLevel.ExploreRecommendations
import com.twitter.visibility.models.SafetyLevel.FilterAll
import com.twitter.visibility.models.SafetyLevel.FilterAllPlaceholder
import com.twitter.visibility.models.SafetyLevel.FilterDefault
import com.twitter.visibility.models.SafetyLevel.FilterNone
import com.twitter.visibility.models.SafetyLevel.FollowedTopicsTimeline
import com.twitter.visibility.models.SafetyLevel.FollowerConnections
import com.twitter.visibility.models.SafetyLevel.FollowingAndFollowersUserList
import com.twitter.visibility.models.SafetyLevel.ForDevelopmentOnly
import com.twitter.visibility.models.SafetyLevel.FriendsFollowingList
import com.twitter.visibility.models.SafetyLevel.GraphqlDefault
import com.twitter.visibility.models.SafetyLevel.GryphonDecksAndColumns
import com.twitter.visibility.models.SafetyLevel.HumanizationNudge
import com.twitter.visibility.models.SafetyLevel.KitchenSinkDevelopment
import com.twitter.visibility.models.SafetyLevel.ListHeader
import com.twitter.visibility.models.SafetyLevel.ListMemberships
import com.twitter.visibility.models.SafetyLevel.ListOwnerships
import com.twitter.visibility.models.SafetyLevel.ListRecommendations
import com.twitter.visibility.models.SafetyLevel.ListSearch
import com.twitter.visibility.models.SafetyLevel.ListSubscriptions
import com.twitter.visibility.models.SafetyLevel.LivePipelineEngagementCounts
import com.twitter.visibility.models.SafetyLevel.LiveVideoTimeline
import com.twitter.visibility.models.SafetyLevel.MagicRecs
import com.twitter.visibility.models.SafetyLevel.MagicRecsAggressive
import com.twitter.visibility.models.SafetyLevel.MagicRecsAggressiveV2
import com.twitter.visibility.models.SafetyLevel.MagicRecsV2
import com.twitter.visibility.models.SafetyLevel.Minimal
import com.twitter.visibility.models.SafetyLevel.ModeratedTweetsTimeline
import com.twitter.visibility.models.SafetyLevel.Moments
import com.twitter.visibility.models.SafetyLevel.NearbyTimeline
import com.twitter.visibility.models.SafetyLevel.NewUserExperience
import com.twitter.visibility.models.SafetyLevel.NotificationsIbis
import com.twitter.visibility.models.SafetyLevel.NotificationsPlatform
import com.twitter.visibility.models.SafetyLevel.NotificationsPlatformPush
import com.twitter.visibility.models.SafetyLevel.NotificationsQig
import com.twitter.visibility.models.SafetyLevel.NotificationsRead
import com.twitter.visibility.models.SafetyLevel.NotificationsTimelineDeviceFollow
import com.twitter.visibility.models.SafetyLevel.NotificationsWrite
import com.twitter.visibility.models.SafetyLevel.NotificationsWriterTweetHydrator
import com.twitter.visibility.models.SafetyLevel.NotificationsWriterV2
import com.twitter.visibility.models.SafetyLevel.ProfileMixerFavorites
import com.twitter.visibility.models.SafetyLevel.ProfileMixerMedia
import com.twitter.visibility.models.SafetyLevel.QuickPromoteTweetEligibility
import com.twitter.visibility.models.SafetyLevel.QuoteTweetTimeline
import com.twitter.visibility.models.SafetyLevel.QuotedTweetRules
import com.twitter.visibility.models.SafetyLevel.RecosVideo
import com.twitter.visibility.models.SafetyLevel.RecosWritePath
import com.twitter.visibility.models.SafetyLevel.RepliesGrouping
import com.twitter.visibility.models.SafetyLevel.ReportCenter
import com.twitter.visibility.models.SafetyLevel.ReturningUserExperienceFocalTweet
import com.twitter.visibility.models.SafetyLevel.Revenue
import com.twitter.visibility.models.SafetyLevel.SafeSearchMinimal
import com.twitter.visibility.models.SafetyLevel.SafeSearchStrict
import com.twitter.visibility.models.SafetyLevel.SearchBlenderUserRules
import com.twitter.visibility.models.SafetyLevel.SearchHydration
import com.twitter.visibility.models.SafetyLevel.SearchLatest
import com.twitter.visibility.models.SafetyLevel.SearchLatestUserRules
import com.twitter.visibility.models.SafetyLevel.SearchMixerSrpMinimal
import com.twitter.visibility.models.SafetyLevel.SearchMixerSrpStrict
import com.twitter.visibility.models.SafetyLevel.SearchPeopleSrp
import com.twitter.visibility.models.SafetyLevel.SearchPeopleTypeahead
import com.twitter.visibility.models.SafetyLevel.SearchPhoto
import com.twitter.visibility.models.SafetyLevel.SearchTop
import com.twitter.visibility.models.SafetyLevel.SearchTopQig
import com.twitter.visibility.models.SafetyLevel.SearchTrendTakeoverPromotedTweet
import com.twitter.visibility.models.SafetyLevel.SearchVideo
import com.twitter.visibility.models.SafetyLevel.ShoppingManagerSpyMode
import com.twitter.visibility.models.SafetyLevel.SignalsReactions
import com.twitter.visibility.models.SafetyLevel.SignalsTweetReactingUsers
import com.twitter.visibility.models.SafetyLevel.SoftInterventionPivot
import com.twitter.visibility.models.SafetyLevel.SpaceFleetline
import com.twitter.visibility.models.SafetyLevel.SpaceHomeTimelineUpranking
import com.twitter.visibility.models.SafetyLevel.SpaceJoinScreen
import com.twitter.visibility.models.SafetyLevel.SpaceNotifications
import com.twitter.visibility.models.SafetyLevel.SpaceTweetAvatarHomeTimeline
import com.twitter.visibility.models.SafetyLevel.SpacesParticipants
import com.twitter.visibility.models.SafetyLevel.SpacesSellerApplicationStatus
import com.twitter.visibility.models.SafetyLevel.SpacesSharing
import com.twitter.visibility.models.SafetyLevel.StickersTimeline
import com.twitter.visibility.models.SafetyLevel.StratoExtLimitedEngagements
import com.twitter.visibility.models.SafetyLevel.StreamServices
import com.twitter.visibility.models.SafetyLevel.SuperFollowerConnections
import com.twitter.visibility.models.SafetyLevel.SuperLike
import com.twitter.visibility.models.SafetyLevel.Test
import com.twitter.visibility.models.SafetyLevel.TimelineBookmark
import com.twitter.visibility.models.SafetyLevel.TimelineContentControls
import com.twitter.visibility.models.SafetyLevel.TimelineConversations
import com.twitter.visibility.models.SafetyLevel.TimelineConversationsDownranking
import com.twitter.visibility.models.SafetyLevel.TimelineConversationsDownrankingMinimal
import com.twitter.visibility.models.SafetyLevel.TimelineFavorites
import com.twitter.visibility.models.SafetyLevel.TimelineFavoritesSelfView
import com.twitter.visibility.models.SafetyLevel.TimelineFocalTweet
import com.twitter.visibility.models.SafetyLevel.TimelineFollowingActivity
import com.twitter.visibility.models.SafetyLevel.TimelineHomeCommunities
import com.twitter.visibility.models.SafetyLevel.TimelineHomeHydration
import com.twitter.visibility.models.SafetyLevel.TimelineHomeLatest
import com.twitter.visibility.models.SafetyLevel.TimelineHomePromotedHydration
import com.twitter.visibility.models.SafetyLevel.TimelineHomeRecommendations
import com.twitter.visibility.models.SafetyLevel.TimelineHomeTopicFollowRecommendations
import com.twitter.visibility.models.SafetyLevel.TimelineInjection
import com.twitter.visibility.models.SafetyLevel.TimelineLikedBy
import com.twitter.visibility.models.SafetyLevel.TimelineLists
import com.twitter.visibility.models.SafetyLevel.TimelineMedia
import com.twitter.visibility.models.SafetyLevel.TimelineMentions
import com.twitter.visibility.models.SafetyLevel.TimelineModeratedTweetsHydration
import com.twitter.visibility.models.SafetyLevel.TimelineProfileAll
import com.twitter.visibility.models.SafetyLevel.TimelineProfileSpaces
import com.twitter.visibility.models.SafetyLevel.TimelineProfileSuperFollows
import com.twitter.visibility.models.SafetyLevel.TimelineScorer
import com.twitter.visibility.models.SafetyLevel.Tombstoning
import com.twitter.visibility.models.SafetyLevel.TopicsLandingPageTopicRecommendations
import com.twitter.visibility.models.SafetyLevel.TrendsRepresentativeTweet
import com.twitter.visibility.models.SafetyLevel.TrustedFriendsUserList
import com.twitter.visibility.models.SafetyLevel.TweetDetail
import com.twitter.visibility.models.SafetyLevel.TweetDetailNonToo
import com.twitter.visibility.models.SafetyLevel.TweetDetailWithInjectionsHydration
import com.twitter.visibility.models.SafetyLevel.TweetEngagers
import com.twitter.visibility.models.SafetyLevel.TweetReplyNudge
import com.twitter.visibility.models.SafetyLevel.TweetWritesApi
import com.twitter.visibility.models.SafetyLevel.TwitterArticleCompose
import com.twitter.visibility.models.SafetyLevel.TwitterArticleProfileTab
import com.twitter.visibility.models.SafetyLevel.TwitterArticleRead
import com.twitter.visibility.models.SafetyLevel.UserMilestoneRecommendation
import com.twitter.visibility.models.SafetyLevel.UserProfileHeader
import com.twitter.visibility.models.SafetyLevel.UserSelfViewOnly
import com.twitter.visibility.models.SafetyLevel.UserSettings
import com.twitter.visibility.models.SafetyLevel.VideoAds
import com.twitter.visibility.models.SafetyLevel.WritePathLimitedActionsEnforcement
import com.twitter.visibility.models.SafetyLevel.ZipbirdConsumerArchives
sealed trait SafetyLevelGroup { val levels: Set[SafetyLevel] }
object SafetyLevelGroup {
case object Ads extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
AdsBusinessSettings,
AdsCampaign,
AdsManager,
AdsReportingDashboard,
BrandSafety,
VideoAds,
QuickPromoteTweetEligibility
)
}
case object ArticleTimeline extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
ArticleTweetTimeline,
)
}
case object ArticleTweets extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
TwitterArticleCompose,
TwitterArticleProfileTab,
TwitterArticleRead,
)
}
case object Birdwatch extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
BirdwatchNoteAuthor,
BirdwatchNoteTweetsTimeline,
BirdwatchNeedsYourHelpNotifications,
)
}
case object Cards extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
CardPollVoting,
CardsService,
)
}
case object Communities extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SafetyLevel.Communities
)
}
case object Conversation extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
ConversationFocalPrehydration,
ConversationFocalTweet,
ConversationInjectedTweet,
ConversationReply,
Tombstoning,
)
}
case object CreativeContainerService extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
AccessInternalPromotedContent
)
}
case object Des extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
DevPlatformGetListTweets,
DesFollowingAndFollowersUserList,
DesHomeTimeline,
DesQuoteTweetTimeline,
DesRetweetingUsers,
DesTweetDetail,
DesTweetLikingUsers,
DesUserBookmarks,
DesUserLikedTweets,
DesUserMentions,
DesUserTweets,
DevPlatformComplianceStream,
)
}
case object DesStream extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
DesRealtime,
DesRealtimeSpamEnrichment,
DesRealtimeTweetFilter,
)
}
case object Dm extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
DirectMessages,
DirectMessagesConversationList,
DirectMessagesConversationTimeline,
DirectMessagesInbox,
DirectMessagesMutedUsers,
DirectMessagesPinned,
DirectMessagesSearch,
)
}
case object Followers extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
FollowedTopicsTimeline,
FollowerConnections,
FollowingAndFollowersUserList,
FriendsFollowingList,
)
}
case object Graphql extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
FilterDefault,
GraphqlDefault,
SoftInterventionPivot,
)
}
case object Jiminy extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
HumanizationNudge,
TweetReplyNudge,
)
}
case object Lists extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
AllSubscribedLists,
ListHeader,
ListMemberships,
ListOwnerships,
ListRecommendations,
ListSearch,
ListSubscriptions,
)
}
case object Notifications extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
NotificationsIbis,
NotificationsPlatform,
NotificationsPlatformPush,
NotificationsQig,
NotificationsRead,
NotificationsTimelineDeviceFollow,
NotificationsWrite,
NotificationsWriterTweetHydrator,
NotificationsWriterV2,
)
}
case object Other extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
CuratedTrendsRepresentativeTweet,
CurationPolicyViolations,
BaseQig,
Appeals,
ContentControlToolInstall,
EditHistoryTimeline,
ElevatedQuoteTweetTimeline,
EmbeddedTweet,
EmbedsPublicInterestNotice,
EmbedTweetMarkup,
ExploreRecommendations,
WritePathLimitedActionsEnforcement,
LiveVideoTimeline,
LivePipelineEngagementCounts,
Minimal,
Moments,
NearbyTimeline,
NewUserExperience,
QuoteTweetTimeline,
QuotedTweetRules,
ReportCenter,
Revenue,
ShoppingManagerSpyMode,
StickersTimeline,
SuperLike,
TrendsRepresentativeTweet,
TrustedFriendsUserList,
GryphonDecksAndColumns,
TweetEngagers,
TweetWritesApi,
UserMilestoneRecommendation,
StreamServices,
ZipbirdConsumerArchives
)
}
case object Profile extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
UserProfileHeader,
UserSelfViewOnly,
UserSettings,
)
}
case object Reactions extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SignalsReactions,
SignalsTweetReactingUsers,
)
}
case object Recommendations extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
MagicRecs,
MagicRecsV2,
MagicRecsAggressive,
MagicRecsAggressiveV2,
SafetyLevel.Recommendations,
RecosVideo,
RecosWritePath,
)
}
case object ReturningUserExperience extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SafetyLevel.ReturningUserExperience,
ReturningUserExperienceFocalTweet,
)
}
case object SafeSearch extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SafeSearchMinimal,
SafeSearchStrict,
)
}
case object Search extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SearchHydration,
SearchLatest,
SearchTop,
SearchTopQig,
SearchPeopleSrp,
SearchPeopleTypeahead,
SearchPhoto,
SearchTrendTakeoverPromotedTweet,
SearchVideo,
SearchBlenderUserRules,
SearchLatestUserRules,
)
}
case object SearchMixer extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SearchMixerSrpMinimal,
SearchMixerSrpStrict,
)
}
case object Socialproof extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SafetyLevel.SocialProof
)
}
case object Spaces extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SpaceFleetline,
SpaceHomeTimelineUpranking,
SpaceJoinScreen,
SpaceNotifications,
SafetyLevel.Spaces,
SpacesParticipants,
SpacesSellerApplicationStatus,
SpacesSharing,
SpaceTweetAvatarHomeTimeline,
)
}
case object Strato extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
StratoExtLimitedEngagements
)
}
case object Superfollows extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SuperFollowerConnections,
TimelineProfileSuperFollows,
)
}
case object Testing extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
ForDevelopmentOnly,
KitchenSinkDevelopment,
Test,
)
}
case object Timeline extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
BlockMuteUsersTimeline,
TimelineBookmark,
TimelineContentControls,
TimelineConversationsDownranking,
TimelineConversationsDownrankingMinimal,
TimelineFavorites,
TimelineFavoritesSelfView,
TimelineFollowingActivity,
TimelineScorer,
TimelineInjection,
TimelineLikedBy,
TimelineLists,
TimelineMedia,
TimelineMentions,
ModeratedTweetsTimeline,
TimelineModeratedTweetsHydration,
)
}
case object TopicRecommendations extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SafetyLevel.TopicRecommendations,
TopicsLandingPageTopicRecommendations,
)
}
case object TimelineProfile extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SafetyLevel.TimelineProfile,
TimelineProfileAll,
TimelineProfileSpaces,
TimelineMedia,
ProfileMixerMedia,
TimelineFavorites,
ProfileMixerFavorites
)
}
case object TimelineHome extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
SafetyLevel.TimelineHome,
TimelineHomeCommunities,
TimelineHomeHydration,
TimelineHomeLatest,
TimelineHomePromotedHydration,
TimelineHomeRecommendations,
TimelineHomeTopicFollowRecommendations,
)
}
case object TlsApi extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
TimelineConversations,
TimelineFocalTweet,
)
}
case object TweetDetails extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
TweetDetail,
TweetDetailNonToo,
TweetDetailWithInjectionsHydration,
RepliesGrouping,
)
}
case object Special extends SafetyLevelGroup {
override val levels: Set[SafetyLevel] = Set(
FilterAll,
FilterAllPlaceholder,
FilterNone,
)
}
}

View File

@ -1,3 +0,0 @@
package com.twitter.visibility.models
case class SemanticCoreAnnotation(groupId: Long, domainId: Long, entityId: Long)

View File

@ -1,91 +0,0 @@
package com.twitter.visibility.models
import com.twitter.visibility.safety_label_store.{thriftscala => s}
import com.twitter.visibility.util.NamingUtils
sealed trait SpaceSafetyLabelType extends SafetyLabelType {
lazy val name: String = NamingUtils.getFriendlyName(this)
}
object SpaceSafetyLabelType extends SafetyLabelType {
val List: List[SpaceSafetyLabelType] = s.SpaceSafetyLabelType.list.map(fromThrift)
val ActiveLabels: List[SpaceSafetyLabelType] = List.filter { labelType =>
labelType != Unknown && labelType != Deprecated
}
private lazy val nameToValueMap: Map[String, SpaceSafetyLabelType] =
List.map(l => l.name.toLowerCase -> l).toMap
def fromName(name: String): Option[SpaceSafetyLabelType] = nameToValueMap.get(name.toLowerCase)
private val UnknownThriftSafetyLabelType =
s.SpaceSafetyLabelType.EnumUnknownSpaceSafetyLabelType(UnknownEnumValue)
private lazy val thriftToModelMap: Map[s.SpaceSafetyLabelType, SpaceSafetyLabelType] = Map(
s.SpaceSafetyLabelType.DoNotAmplify -> DoNotAmplify,
s.SpaceSafetyLabelType.CoordinatedHarmfulActivityHighRecall -> CoordinatedHarmfulActivityHighRecall,
s.SpaceSafetyLabelType.UntrustedUrl -> UntrustedUrl,
s.SpaceSafetyLabelType.MisleadingHighRecall -> MisleadingHighRecall,
s.SpaceSafetyLabelType.NsfwHighPrecision -> NsfwHighPrecision,
s.SpaceSafetyLabelType.NsfwHighRecall -> NsfwHighRecall,
s.SpaceSafetyLabelType.CivicIntegrityMisinfo -> CivicIntegrityMisinfo,
s.SpaceSafetyLabelType.MedicalMisinfo -> MedicalMisinfo,
s.SpaceSafetyLabelType.GenericMisinfo -> GenericMisinfo,
s.SpaceSafetyLabelType.DmcaWithheld -> DmcaWithheld,
s.SpaceSafetyLabelType.HatefulHighRecall -> HatefulHighRecall,
s.SpaceSafetyLabelType.ViolenceHighRecall -> ViolenceHighRecall,
s.SpaceSafetyLabelType.HighToxicityModelScore -> HighToxicityModelScore,
s.SpaceSafetyLabelType.DeprecatedSpaceSafetyLabel14 -> Deprecated,
s.SpaceSafetyLabelType.DeprecatedSpaceSafetyLabel15 -> Deprecated,
s.SpaceSafetyLabelType.Reserved16 -> Deprecated,
s.SpaceSafetyLabelType.Reserved17 -> Deprecated,
s.SpaceSafetyLabelType.Reserved18 -> Deprecated,
s.SpaceSafetyLabelType.Reserved19 -> Deprecated,
s.SpaceSafetyLabelType.Reserved20 -> Deprecated,
s.SpaceSafetyLabelType.Reserved21 -> Deprecated,
s.SpaceSafetyLabelType.Reserved22 -> Deprecated,
s.SpaceSafetyLabelType.Reserved23 -> Deprecated,
s.SpaceSafetyLabelType.Reserved24 -> Deprecated,
s.SpaceSafetyLabelType.Reserved25 -> Deprecated,
)
private lazy val modelToThriftMap: Map[SpaceSafetyLabelType, s.SpaceSafetyLabelType] =
(for ((k, v) <- thriftToModelMap) yield (v, k)) ++ Map(
Deprecated -> s.SpaceSafetyLabelType.EnumUnknownSpaceSafetyLabelType(DeprecatedEnumValue),
)
case object DoNotAmplify extends SpaceSafetyLabelType
case object CoordinatedHarmfulActivityHighRecall extends SpaceSafetyLabelType
case object UntrustedUrl extends SpaceSafetyLabelType
case object MisleadingHighRecall extends SpaceSafetyLabelType
case object NsfwHighPrecision extends SpaceSafetyLabelType
case object NsfwHighRecall extends SpaceSafetyLabelType
case object CivicIntegrityMisinfo extends SpaceSafetyLabelType
case object MedicalMisinfo extends SpaceSafetyLabelType
case object GenericMisinfo extends SpaceSafetyLabelType
case object DmcaWithheld extends SpaceSafetyLabelType
case object HatefulHighRecall extends SpaceSafetyLabelType
case object ViolenceHighRecall extends SpaceSafetyLabelType
case object HighToxicityModelScore extends SpaceSafetyLabelType
case object Deprecated extends SpaceSafetyLabelType
case object Unknown extends SpaceSafetyLabelType
def fromThrift(safetyLabelType: s.SpaceSafetyLabelType): SpaceSafetyLabelType =
thriftToModelMap.get(safetyLabelType) match {
case Some(spaceSafetyLabelType) => spaceSafetyLabelType
case _ =>
safetyLabelType match {
case s.SpaceSafetyLabelType.EnumUnknownSpaceSafetyLabelType(DeprecatedEnumValue) =>
Deprecated
case _ =>
Unknown
}
}
def toThrift(safetyLabelType: SpaceSafetyLabelType): s.SpaceSafetyLabelType = {
modelToThriftMap
.get(safetyLabelType).getOrElse(UnknownThriftSafetyLabelType)
}
}

View File

@ -1,6 +0,0 @@
package com.twitter.visibility.models
object TweetDeleteReason extends Enumeration {
type TweetDeleteReason = Value
val Deleted, BounceDeleted = Value
}

View File

@ -1,23 +0,0 @@
package com.twitter.visibility.models
import com.twitter.spam.rtf.{thriftscala => s}
case class TweetModelMetadata(
version: Option[Int] = None,
calibratedLanguage: Option[String] = None)
object TweetModelMetadata {
def fromThrift(metadata: s.ModelMetadata): Option[TweetModelMetadata] = {
metadata match {
case s.ModelMetadata.ModelMetadataV1(s.ModelMetadataV1(version, calibratedLanguage)) =>
Some(TweetModelMetadata(version, calibratedLanguage))
case _ => None
}
}
def toThrift(metadata: TweetModelMetadata): s.ModelMetadata = {
s.ModelMetadata.ModelMetadataV1(
s.ModelMetadataV1(metadata.version, metadata.calibratedLanguage))
}
}

View File

@ -1,360 +0,0 @@
package com.twitter.visibility.models
import com.twitter.spam.rtf.thriftscala.SafetyLabelSource
import com.twitter.spam.rtf.{thriftscala => s}
import com.twitter.util.Time
import com.twitter.visibility.util.NamingUtils
sealed trait TweetSafetyLabelType extends SafetyLabelType with Product with Serializable {
lazy val name: String = NamingUtils.getFriendlyName(this)
}
case class TweetSafetyLabel(
labelType: TweetSafetyLabelType,
source: Option[LabelSource] = None,
applicableUsers: Set[Long] = Set.empty,
modelMetadata: Option[TweetModelMetadata] = None,
score: Option[Double] = None,
safetyLabelSource: Option[SafetyLabelSource] = None)
object TweetSafetyLabelType extends SafetyLabelType {
val List: List[TweetSafetyLabelType] = s.SafetyLabelType.list.map(fromThrift)
val ActiveLabels: List[TweetSafetyLabelType] = List.filter { labelType =>
labelType != Unknown && labelType != Deprecated
}
private lazy val nameToValueMap: Map[String, TweetSafetyLabelType] =
List.map(l => l.name.toLowerCase -> l).toMap
def fromName(name: String): Option[TweetSafetyLabelType] = nameToValueMap.get(name.toLowerCase)
private val UnknownThriftSafetyLabelType =
s.SafetyLabelType.EnumUnknownSafetyLabelType(UnknownEnumValue)
private lazy val thriftToModelMap: Map[s.SafetyLabelType, TweetSafetyLabelType] = Map(
s.SafetyLabelType.Abusive -> Abusive,
s.SafetyLabelType.AbusiveBehavior -> AbusiveBehavior,
s.SafetyLabelType.AbusiveBehaviorInsults -> AbusiveBehaviorInsults,
s.SafetyLabelType.AbusiveBehaviorViolentThreat -> AbusiveBehaviorViolentThreat,
s.SafetyLabelType.AbusiveBehaviorMajorAbuse -> AbusiveBehaviorMajorAbuse,
s.SafetyLabelType.AbusiveHighRecall -> AbusiveHighRecall,
s.SafetyLabelType.AdsManagerDenyList -> AdsManagerDenyList,
s.SafetyLabelType.AgathaSpam -> AgathaSpam,
s.SafetyLabelType.Automation -> Automation,
s.SafetyLabelType.AutomationHighRecall -> AutomationHighRecall,
s.SafetyLabelType.Bounce -> Bounce,
s.SafetyLabelType.BounceEdits -> BounceEdits,
s.SafetyLabelType.BrandSafetyNsfaAggregate -> BrandSafetyNsfaAggregate,
s.SafetyLabelType.BrandSafetyExperimental1 -> BrandSafetyExperimental1,
s.SafetyLabelType.BrandSafetyExperimental2 -> BrandSafetyExperimental2,
s.SafetyLabelType.BrandSafetyExperimental3 -> BrandSafetyExperimental3,
s.SafetyLabelType.BrandSafetyExperimental4 -> BrandSafetyExperimental4,
s.SafetyLabelType.BystanderAbusive -> BystanderAbusive,
s.SafetyLabelType.CopypastaSpam -> CopypastaSpam,
s.SafetyLabelType.DoNotAmplify -> DoNotAmplify,
s.SafetyLabelType.DownrankSpamReply -> DownrankSpamReply,
s.SafetyLabelType.DuplicateContent -> DuplicateContent,
s.SafetyLabelType.DuplicateMention -> DuplicateMention,
s.SafetyLabelType.DynamicProductAd -> DynamicProductAd,
s.SafetyLabelType.EdiDevelopmentOnly -> EdiDevelopmentOnly,
s.SafetyLabelType.ExperimentalNudge -> ExperimentalNudge,
s.SafetyLabelType.ExperimentalSensitiveIllegal2 -> ExperimentalSensitiveIllegal2,
s.SafetyLabelType.ForEmergencyUseOnly -> ForEmergencyUseOnly,
s.SafetyLabelType.GoreAndViolence -> GoreAndViolence,
s.SafetyLabelType.GoreAndViolenceHighPrecision -> GoreAndViolenceHighPrecision,
s.SafetyLabelType.GoreAndViolenceHighRecall -> GoreAndViolenceHighRecall,
s.SafetyLabelType.GoreAndViolenceReportedHeuristics -> GoreAndViolenceReportedHeuristics,
s.SafetyLabelType.GoreAndViolenceTopicHighRecall -> GoreAndViolenceTopicHighRecall,
s.SafetyLabelType.HatefulConduct -> HatefulConduct,
s.SafetyLabelType.HatefulConductViolentThreat -> HatefulConductViolentThreat,
s.SafetyLabelType.HighCryptospamScore -> HighCryptospamScore,
s.SafetyLabelType.HighPReportedTweetScore -> HighPReportedTweetScore,
s.SafetyLabelType.HighPSpammyTweetScore -> HighPSpammyTweetScore,
s.SafetyLabelType.HighPblockScore -> HighPblockScore,
s.SafetyLabelType.HighProactiveTosScore -> HighProactiveTosScore,
s.SafetyLabelType.HighSpammyTweetContentScore -> HighSpammyTweetContentScore,
s.SafetyLabelType.HighToxicityScore -> HighToxicityScore,
s.SafetyLabelType.HighlyReportedAndMidhighToxicityScore -> HighlyReportedAndMidhighToxicityScore,
s.SafetyLabelType.HighlyReportedTweet -> HighlyReportedTweet,
s.SafetyLabelType.InterstitialDevelopmentOnly -> InterstitialDevelopmentOnly,
s.SafetyLabelType.IpiDevelopmentOnly -> IpiDevelopmentOnly,
s.SafetyLabelType.LiveLowQuality -> LiveLowQuality,
s.SafetyLabelType.LowQuality -> LowQuality,
s.SafetyLabelType.LowQualityMention -> LowQualityMention,
s.SafetyLabelType.MisinfoCivic -> MisinfoCivic,
s.SafetyLabelType.MisinfoCrisis -> MisinfoCrisis,
s.SafetyLabelType.MisinfoGeneric -> MisinfoGeneric,
s.SafetyLabelType.MisinfoMedical -> MisinfoMedical,
s.SafetyLabelType.NsfaHighPrecision -> NsfaHighPrecision,
s.SafetyLabelType.NsfaHighRecall -> NsfaHighRecall,
s.SafetyLabelType.NsfwCardImage -> NsfwCardImage,
s.SafetyLabelType.NsfwHighPrecision -> NsfwHighPrecision,
s.SafetyLabelType.NsfwHighRecall -> NsfwHighRecall,
s.SafetyLabelType.NsfwReportedHeuristics -> NsfwReportedHeuristics,
s.SafetyLabelType.NsfwText -> NsfwText,
s.SafetyLabelType.NsfwTextHighPrecision -> NsfwTextHighPrecision,
s.SafetyLabelType.NsfwVideo -> NsfwVideo,
s.SafetyLabelType.PNegMultimodalHighPrecision -> PNegMultimodalHighPrecision,
s.SafetyLabelType.PNegMultimodalHighRecall -> PNegMultimodalHighRecall,
s.SafetyLabelType.Pdna -> Pdna,
s.SafetyLabelType.RecommendationsLowQuality -> RecommendationsLowQuality,
s.SafetyLabelType.RitoActionedTweet -> RitoActionedTweet,
s.SafetyLabelType.SafetyCrisis -> SafetyCrisis,
s.SafetyLabelType.SearchBlacklist -> SearchBlacklist,
s.SafetyLabelType.SearchBlacklistHighRecall -> SearchBlacklistHighRecall,
s.SafetyLabelType.SemanticCoreMisinformation -> SemanticCoreMisinformation,
s.SafetyLabelType.SmyteSpamTweet -> SmyteSpamTweet,
s.SafetyLabelType.Spam -> Spam,
s.SafetyLabelType.SpamHighRecall -> SpamHighRecall,
s.SafetyLabelType.TombstoneDevelopmentOnly -> TombstoneDevelopmentOnly,
s.SafetyLabelType.TweetContainsHatefulConductSlurHighSeverity -> TweetContainsHatefulConductSlurHighSeverity,
s.SafetyLabelType.TweetContainsHatefulConductSlurMediumSeverity -> TweetContainsHatefulConductSlurMediumSeverity,
s.SafetyLabelType.TweetContainsHatefulConductSlurLowSeverity -> TweetContainsHatefulConductSlurLowSeverity,
s.SafetyLabelType.UnsafeUrl -> UnsafeUrl,
s.SafetyLabelType.UntrustedUrl -> UntrustedUrl,
s.SafetyLabelType.FosnrHatefulConduct -> FosnrHatefulConduct,
s.SafetyLabelType.FosnrHatefulConductLowSeveritySlur -> FosnrHatefulConductLowSeveritySlur,
s.SafetyLabelType.AbusiveHighRecall2 -> Deprecated,
s.SafetyLabelType.AbusiveHighRecall3 -> Deprecated,
s.SafetyLabelType.BrazilianPoliticalTweet -> Deprecated,
s.SafetyLabelType.BystanderAbusive2 -> Deprecated,
s.SafetyLabelType.BystanderAbusive3 -> Deprecated,
s.SafetyLabelType.DeprecatedLabel144 -> Deprecated,
s.SafetyLabelType.Experimental10Seh -> Deprecated,
s.SafetyLabelType.Experimental11Seh -> Deprecated,
s.SafetyLabelType.Experimental12Seh -> Deprecated,
s.SafetyLabelType.Experimental13Seh -> Deprecated,
s.SafetyLabelType.Experimental14Seh -> Deprecated,
s.SafetyLabelType.Experimental15Seh -> Deprecated,
s.SafetyLabelType.Experimental16Seh -> Deprecated,
s.SafetyLabelType.Experimental17Seh -> Deprecated,
s.SafetyLabelType.Experimental18Seh -> Deprecated,
s.SafetyLabelType.Experimental19Seh -> Deprecated,
s.SafetyLabelType.Experimental1Seh -> Deprecated,
s.SafetyLabelType.Experimental20Seh -> Deprecated,
s.SafetyLabelType.Experimental21Seh -> Deprecated,
s.SafetyLabelType.Experimental22Seh -> Deprecated,
s.SafetyLabelType.Experimental23Seh -> Deprecated,
s.SafetyLabelType.Experimental24Seh -> Deprecated,
s.SafetyLabelType.Experimental25Seh -> Deprecated,
s.SafetyLabelType.Experimental2Seh -> Deprecated,
s.SafetyLabelType.Experimental3Seh -> Deprecated,
s.SafetyLabelType.Experimental4Seh -> Deprecated,
s.SafetyLabelType.Experimental5Seh -> Deprecated,
s.SafetyLabelType.Experimental6Seh -> Deprecated,
s.SafetyLabelType.Experimental7Seh -> Deprecated,
s.SafetyLabelType.Experimental8Seh -> Deprecated,
s.SafetyLabelType.Experimental9Seh -> Deprecated,
s.SafetyLabelType.ExperimentalHighHealthModelScore1 -> Deprecated,
s.SafetyLabelType.ExperimentalHighHealthModelScore10 -> Deprecated,
s.SafetyLabelType.ExperimentalHighHealthModelScore2 -> Deprecated,
s.SafetyLabelType.ExperimentalHighHealthModelScore3 -> Deprecated,
s.SafetyLabelType.ExperimentalHighHealthModelScore4 -> Deprecated,
s.SafetyLabelType.ExperimentalHighHealthModelScore5 -> Deprecated,
s.SafetyLabelType.ExperimentalHighHealthModelScore6 -> Deprecated,
s.SafetyLabelType.ExperimentalHighHealthModelScore7 -> Deprecated,
s.SafetyLabelType.ExperimentalHighHealthModelScore8 -> Deprecated,
s.SafetyLabelType.ExperimentalHighHealthModelScore9 -> Deprecated,
s.SafetyLabelType.ExperimentalSensitiveIllegal1 -> Deprecated,
s.SafetyLabelType.ExperimentalSensitiveIllegal3 -> Deprecated,
s.SafetyLabelType.ExperimentalSensitiveIllegal4 -> Deprecated,
s.SafetyLabelType.ExperimentalSensitiveIllegal5 -> Deprecated,
s.SafetyLabelType.ExperimentalSensitiveIllegal6 -> Deprecated,
s.SafetyLabelType.ExperimentalSpam1 -> Deprecated,
s.SafetyLabelType.ExperimentalSpam2 -> Deprecated,
s.SafetyLabelType.ExperimentalSpam3 -> Deprecated,
s.SafetyLabelType.Experimentation -> Deprecated,
s.SafetyLabelType.Experimentation2 -> Deprecated,
s.SafetyLabelType.Experimentation3 -> Deprecated,
s.SafetyLabelType.HighlyReportedImage -> Deprecated,
s.SafetyLabelType.HighToxicityHoldbackModelScore -> Deprecated,
s.SafetyLabelType.LowQualityHighRecall -> Deprecated,
s.SafetyLabelType.MagicRecsDenylist -> Deprecated,
s.SafetyLabelType.MisinfoCovid19 -> Deprecated,
s.SafetyLabelType.MsnfoBrazilianElection -> Deprecated,
s.SafetyLabelType.MsnfoCovid19Vaccine -> Deprecated,
s.SafetyLabelType.MsnfoFrenchElection -> Deprecated,
s.SafetyLabelType.MsnfoPhilippineElection -> Deprecated,
s.SafetyLabelType.MsnfoUsElection -> Deprecated,
s.SafetyLabelType.NsfwNearPerfect -> Deprecated,
s.SafetyLabelType.PersonaNonGrata -> Deprecated,
s.SafetyLabelType.PMisinfoCombined15 -> Deprecated,
s.SafetyLabelType.PMisinfoCombined30 -> Deprecated,
s.SafetyLabelType.PMisinfoCombined50 -> Deprecated,
s.SafetyLabelType.PMisinfoDenylist -> Deprecated,
s.SafetyLabelType.PMisinfoPVeracityNudge -> Deprecated,
s.SafetyLabelType.PoliticalTweetExperimental1 -> Deprecated,
s.SafetyLabelType.ProactiveTosHighRecall -> Deprecated,
s.SafetyLabelType.ProactiveTosHighRecallContainsSelfHarm -> Deprecated,
s.SafetyLabelType.ProactiveTosHighRecallEncourageSelfHarm -> Deprecated,
s.SafetyLabelType.ProactiveTosHighRecallEpisodic -> Deprecated,
s.SafetyLabelType.ProactiveTosHighRecallEpisodicHatefulConduct -> Deprecated,
s.SafetyLabelType.ProactiveTosHighRecallOtherAbusePolicy -> Deprecated,
s.SafetyLabelType.ProjectLibra -> Deprecated,
s.SafetyLabelType.SearchHighVisibilityDenylist -> Deprecated,
s.SafetyLabelType.SearchHighVisibilityHighRecallDenylist -> Deprecated,
s.SafetyLabelType.Reserved162 -> Deprecated,
s.SafetyLabelType.Reserved163 -> Deprecated,
s.SafetyLabelType.Reserved164 -> Deprecated,
s.SafetyLabelType.Reserved165 -> Deprecated,
s.SafetyLabelType.Reserved166 -> Deprecated,
s.SafetyLabelType.Reserved167 -> Deprecated,
s.SafetyLabelType.Reserved168 -> Deprecated,
s.SafetyLabelType.Reserved169 -> Deprecated,
s.SafetyLabelType.Reserved170 -> Deprecated,
)
private lazy val modelToThriftMap: Map[TweetSafetyLabelType, s.SafetyLabelType] =
(for ((k, v) <- thriftToModelMap) yield (v, k)) ++ Map(
Deprecated -> s.SafetyLabelType.EnumUnknownSafetyLabelType(DeprecatedEnumValue),
)
case object Abusive extends TweetSafetyLabelType
case object AbusiveBehavior extends TweetSafetyLabelType
case object AbusiveBehaviorInsults extends TweetSafetyLabelType
case object AbusiveBehaviorViolentThreat extends TweetSafetyLabelType
case object AbusiveBehaviorMajorAbuse extends TweetSafetyLabelType
case object AbusiveHighRecall extends TweetSafetyLabelType
case object Automation extends TweetSafetyLabelType
case object AutomationHighRecall extends TweetSafetyLabelType
case object Bounce extends TweetSafetyLabelType
case object BystanderAbusive extends TweetSafetyLabelType
case object NsfaHighRecall extends TweetSafetyLabelType
case object DuplicateContent extends TweetSafetyLabelType
case object DuplicateMention extends TweetSafetyLabelType
case object GoreAndViolence extends TweetSafetyLabelType {
val DeprecatedAt: Time = Time.at("2019-09-12 00:00:00 UTC")
}
case object GoreAndViolenceHighRecall extends TweetSafetyLabelType
case object LiveLowQuality extends TweetSafetyLabelType
case object LowQuality extends TweetSafetyLabelType
case object LowQualityMention extends TweetSafetyLabelType
case object NsfwCardImage extends TweetSafetyLabelType
case object NsfwHighRecall extends TweetSafetyLabelType
case object NsfwHighPrecision extends TweetSafetyLabelType
case object NsfwVideo extends TweetSafetyLabelType
case object Pdna extends TweetSafetyLabelType
case object RecommendationsLowQuality extends TweetSafetyLabelType
case object SearchBlacklist extends TweetSafetyLabelType
case object Spam extends TweetSafetyLabelType
case object SpamHighRecall extends TweetSafetyLabelType
case object UntrustedUrl extends TweetSafetyLabelType
case object HighToxicityScore extends TweetSafetyLabelType
case object HighPblockScore extends TweetSafetyLabelType
case object SearchBlacklistHighRecall extends TweetSafetyLabelType
case object ForEmergencyUseOnly extends TweetSafetyLabelType
case object HighProactiveTosScore extends TweetSafetyLabelType
case object SafetyCrisis extends TweetSafetyLabelType
case object MisinfoCivic extends TweetSafetyLabelType
case object MisinfoCrisis extends TweetSafetyLabelType
case object MisinfoGeneric extends TweetSafetyLabelType
case object MisinfoMedical extends TweetSafetyLabelType
case object AdsManagerDenyList extends TweetSafetyLabelType
case object GoreAndViolenceHighPrecision extends TweetSafetyLabelType
case object NsfwReportedHeuristics extends TweetSafetyLabelType
case object GoreAndViolenceReportedHeuristics extends TweetSafetyLabelType
case object HighPSpammyTweetScore extends TweetSafetyLabelType
case object DoNotAmplify extends TweetSafetyLabelType
case object HighlyReportedTweet extends TweetSafetyLabelType
case object AgathaSpam extends TweetSafetyLabelType
case object SmyteSpamTweet extends TweetSafetyLabelType
case object SemanticCoreMisinformation extends TweetSafetyLabelType
case object HighPReportedTweetScore extends TweetSafetyLabelType
case object HighSpammyTweetContentScore extends TweetSafetyLabelType
case object GoreAndViolenceTopicHighRecall extends TweetSafetyLabelType
case object CopypastaSpam extends TweetSafetyLabelType
case object ExperimentalSensitiveIllegal2 extends TweetSafetyLabelType
case object DownrankSpamReply extends TweetSafetyLabelType
case object NsfwText extends TweetSafetyLabelType
case object HighlyReportedAndMidhighToxicityScore extends TweetSafetyLabelType
case object DynamicProductAd extends TweetSafetyLabelType
case object TombstoneDevelopmentOnly extends TweetSafetyLabelType
case object TweetContainsHatefulConductSlurHighSeverity extends TweetSafetyLabelType
case object TweetContainsHatefulConductSlurMediumSeverity extends TweetSafetyLabelType
case object TweetContainsHatefulConductSlurLowSeverity extends TweetSafetyLabelType
case object RitoActionedTweet extends TweetSafetyLabelType
case object ExperimentalNudge extends TweetSafetyLabelType
case object PNegMultimodalHighPrecision extends TweetSafetyLabelType
case object PNegMultimodalHighRecall extends TweetSafetyLabelType
case object BrandSafetyNsfaAggregate extends TweetSafetyLabelType
case object HighCryptospamScore extends TweetSafetyLabelType
case object IpiDevelopmentOnly extends TweetSafetyLabelType
case object BounceEdits extends TweetSafetyLabelType
case object UnsafeUrl extends TweetSafetyLabelType
case object InterstitialDevelopmentOnly extends TweetSafetyLabelType
case object EdiDevelopmentOnly extends TweetSafetyLabelType
case object NsfwTextHighPrecision extends TweetSafetyLabelType
case object HatefulConduct extends TweetSafetyLabelType
case object HatefulConductViolentThreat extends TweetSafetyLabelType
case object NsfaHighPrecision extends TweetSafetyLabelType
case object BrandSafetyExperimental1 extends TweetSafetyLabelType
case object BrandSafetyExperimental2 extends TweetSafetyLabelType
case object BrandSafetyExperimental3 extends TweetSafetyLabelType
case object BrandSafetyExperimental4 extends TweetSafetyLabelType
case object FosnrHatefulConduct extends TweetSafetyLabelType
case object FosnrHatefulConductLowSeveritySlur extends TweetSafetyLabelType
case object Deprecated extends TweetSafetyLabelType
case object Unknown extends TweetSafetyLabelType
def fromThrift(safetyLabelType: s.SafetyLabelType): TweetSafetyLabelType =
thriftToModelMap.get(safetyLabelType) match {
case Some(tweetSafetyLabelType) => tweetSafetyLabelType
case _ =>
safetyLabelType match {
case s.SafetyLabelType.EnumUnknownSafetyLabelType(DeprecatedEnumValue) => Deprecated
case _ =>
Unknown
}
}
def toThrift(safetyLabelType: TweetSafetyLabelType): s.SafetyLabelType = {
modelToThriftMap.getOrElse(safetyLabelType, UnknownThriftSafetyLabelType)
}
}
object TweetSafetyLabel {
def fromThrift(safetyLabelValue: s.SafetyLabelValue): TweetSafetyLabel =
fromTuple(safetyLabelValue.labelType, safetyLabelValue.label)
def fromTuple(
safetyLabelType: s.SafetyLabelType,
safetyLabel: s.SafetyLabel
): TweetSafetyLabel = {
TweetSafetyLabel(
labelType = TweetSafetyLabelType.fromThrift(safetyLabelType),
source = safetyLabel.source.flatMap(LabelSource.fromString),
safetyLabelSource = safetyLabel.safetyLabelSource,
applicableUsers = safetyLabel.applicableUsers
.map { perspectivalUsers =>
(perspectivalUsers map {
_.userId
}).toSet
}.getOrElse(Set.empty),
score = safetyLabel.score,
modelMetadata = safetyLabel.modelMetadata.flatMap(TweetModelMetadata.fromThrift)
)
}
def toThrift(tweetSafetyLabel: TweetSafetyLabel): s.SafetyLabelValue = {
s.SafetyLabelValue(
labelType = TweetSafetyLabelType.toThrift(tweetSafetyLabel.labelType),
label = s.SafetyLabel(
applicableUsers = if (tweetSafetyLabel.applicableUsers.nonEmpty) {
Some(tweetSafetyLabel.applicableUsers.toSeq.map {
s.PerspectivalUser(_)
})
} else {
None
},
source = tweetSafetyLabel.source.map(_.name),
score = tweetSafetyLabel.score,
modelMetadata = tweetSafetyLabel.modelMetadata.map(TweetModelMetadata.toThrift)
)
)
}
}

View File

@ -1,16 +0,0 @@
package com.twitter.visibility.models
trait UnitOfDiversion {
def apply: (String, Any)
}
object UnitOfDiversion {
case class ConversationId(conversationId: Long) extends UnitOfDiversion {
override def apply: (String, Any) = ("conversation_id", conversationId)
}
case class TweetId(tweetId: Long) extends UnitOfDiversion {
override def apply: (String, Any) = ("tweet_id", tweetId)
}
}

Some files were not shown because too many files have changed in this diff Show More