mirror of
https://github.com/twitter/the-algorithm.git
synced 2024-11-16 00:25:11 +01:00
[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:
parent
e90b21ec83
commit
c53a0a714d
Binary file not shown.
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
@ -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",
|
||||
],
|
||||
)
|
Binary file not shown.
Binary file not shown.
@ -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))
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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))
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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
|
||||
}
|
Binary file not shown.
@ -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,
|
||||
)
|
Binary file not shown.
@ -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))
|
||||
|
||||
}
|
@ -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",
|
||||
],
|
||||
)
|
Binary file not shown.
Binary file not shown.
@ -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)
|
Binary file not shown.
@ -1,5 +0,0 @@
|
||||
package com.twitter.visibility.interfaces.search
|
||||
|
||||
case class BatchSearchVisibilityResponse(
|
||||
visibilityResults: Map[Long, CombinedVisibilityResult],
|
||||
failedTweetIds: Seq[Long])
|
Binary file not shown.
@ -1,7 +0,0 @@
|
||||
package com.twitter.visibility.interfaces.search
|
||||
|
||||
import com.twitter.visibility.builder.VisibilityResult
|
||||
|
||||
case class CombinedVisibilityResult(
|
||||
tweetVisibilityResult: VisibilityResult,
|
||||
quotedTweetVisibilityResult: Option[VisibilityResult])
|
Binary file not shown.
@ -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)
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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)
|
@ -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",
|
||||
],
|
||||
)
|
Binary file not shown.
Binary file not shown.
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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]])
|
@ -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",
|
||||
],
|
||||
)
|
Binary file not shown.
Binary file not shown.
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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)
|
Binary file not shown.
@ -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)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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,
|
||||
)
|
@ -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",
|
||||
],
|
||||
)
|
Binary file not shown.
Binary file not shown.
@ -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
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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)
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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",
|
||||
],
|
||||
)
|
Binary file not shown.
Binary file not shown.
@ -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
|
||||
)
|
||||
)
|
||||
}
|
@ -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",
|
||||
],
|
||||
)
|
Binary file not shown.
Binary file not shown.
@ -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)
|
Binary file not shown.
@ -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
|
||||
}
|
Binary file not shown.
@ -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
|
||||
}
|
Binary file not shown.
@ -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)
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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
|
||||
}
|
Binary file not shown.
@ -1,3 +0,0 @@
|
||||
package com.twitter.visibility.models
|
||||
|
||||
case class MutedKeyword(keyword: Option[String])
|
Binary file not shown.
@ -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)
|
||||
)
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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
|
||||
)
|
||||
}
|
||||
}
|
Binary file not shown.
@ -1,7 +0,0 @@
|
||||
package com.twitter.visibility.models
|
||||
|
||||
trait SafetyLabelType {
|
||||
val DeprecatedEnumValue: Short = -1
|
||||
val UnknownEnumValue: Short = -2
|
||||
val StratoOnlyLabelEnumValue: Short = -3
|
||||
}
|
Binary file not shown.
@ -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)
|
||||
}
|
Binary file not shown.
@ -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,
|
||||
)
|
||||
}
|
||||
}
|
Binary file not shown.
@ -1,3 +0,0 @@
|
||||
package com.twitter.visibility.models
|
||||
|
||||
case class SemanticCoreAnnotation(groupId: Long, domainId: Long, entityId: Long)
|
Binary file not shown.
@ -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)
|
||||
}
|
||||
}
|
Binary file not shown.
@ -1,6 +0,0 @@
|
||||
package com.twitter.visibility.models
|
||||
|
||||
object TweetDeleteReason extends Enumeration {
|
||||
type TweetDeleteReason = Value
|
||||
val Deleted, BounceDeleted = Value
|
||||
}
|
Binary file not shown.
@ -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))
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
Binary file not shown.
@ -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
Loading…
Reference in New Issue
Block a user