Merge pull request #9098 from niklasf/mention-pref

opt-out of forum mentions (closes #9069)
pull/9111/head
Thibault Duplessis 2021-06-04 10:43:54 +02:00 committed by GitHub
commit a940235095
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 42 additions and 11 deletions

View File

@ -169,6 +169,10 @@ object pref {
trans.letOtherPlayersInviteYouToStudy(), trans.letOtherPlayersInviteYouToStudy(),
radios(form("studyInvite"), translatedStudyInviteChoices) radios(form("studyInvite"), translatedStudyInviteChoices)
), ),
setting(
trans.receiveForumNotifications(),
radios(form("mention"), booleanChoices)
),
setting( setting(
trans.shareYourInsightsData(), trans.shareYourInsightsData(),
radios(form("insightShare"), translatedInsightShareChoices) radios(form("insightShare"), translatedInsightShareChoices)

View File

@ -9,6 +9,7 @@ import lila.hub.actorApi.team.CreateTeam
import lila.mod.ModlogApi import lila.mod.ModlogApi
import lila.notify.NotifyApi import lila.notify.NotifyApi
import lila.relation.RelationApi import lila.relation.RelationApi
import lila.pref.PrefApi
import play.api.libs.ws.StandaloneWSClient import play.api.libs.ws.StandaloneWSClient
@Module @Module
@ -30,6 +31,7 @@ final class Env(
forumSearch: lila.hub.actors.ForumSearch, forumSearch: lila.hub.actors.ForumSearch,
notifyApi: NotifyApi, notifyApi: NotifyApi,
relationApi: RelationApi, relationApi: RelationApi,
prefApi: PrefApi,
userRepo: lila.user.UserRepo, userRepo: lila.user.UserRepo,
cacheApi: lila.memo.CacheApi, cacheApi: lila.memo.CacheApi,
ws: StandaloneWSClient ws: StandaloneWSClient

View File

@ -4,6 +4,7 @@ import lila.common.Future
import lila.notify.NotifyApi import lila.notify.NotifyApi
import lila.notify.{ MentionedInThread, Notification } import lila.notify.{ MentionedInThread, Notification }
import lila.relation.RelationApi import lila.relation.RelationApi
import lila.pref.PrefApi
import lila.user.{ User, UserRepo } import lila.user.{ User, UserRepo }
/** Notifier to inform users if they have been mentioned in a post /** Notifier to inform users if they have been mentioned in a post
@ -13,11 +14,10 @@ import lila.user.{ User, UserRepo }
final class MentionNotifier( final class MentionNotifier(
userRepo: UserRepo, userRepo: UserRepo,
notifyApi: NotifyApi, notifyApi: NotifyApi,
relationApi: RelationApi relationApi: RelationApi,
prefApi: PrefApi
)(implicit ec: scala.concurrent.ExecutionContext) { )(implicit ec: scala.concurrent.ExecutionContext) {
private val forbidden = Set("lichess", "thibault")
def notifyMentionedUsers(post: Post, topic: Topic): Funit = def notifyMentionedUsers(post: Post, topic: Topic): Funit =
post.userId.ifFalse(post.troll) ?? { author => post.userId.ifFalse(post.troll) ?? { author =>
filterValidUsers(extractMentionedUsers(post), author) flatMap { validUsers => filterValidUsers(extractMentionedUsers(post), author) flatMap { validUsers =>
@ -30,15 +30,18 @@ final class MentionNotifier(
/** Checks the database to make sure that the users mentioned exist, and removes any users that do not exist /** Checks the database to make sure that the users mentioned exist, and removes any users that do not exist
* or block the mentioner from the returned list. * or block the mentioner from the returned list.
*/ */
private def filterValidUsers(users: Set[User.ID], mentionedBy: User.ID): Fu[List[Notification.Notifies]] = { private def filterValidUsers(
candidates: Set[User.ID],
mentionedBy: User.ID
): Fu[List[Notification.Notifies]] = {
for { for {
validUsers <- existingUsers <-
userRepo userRepo
.existingUsernameIds(users take 10 diff forbidden) .existingUsernameIds(candidates take 10)
.map(_ take 5) .map(_.take(5).toSet)
validUnblockedUsers <- filterNotBlockedByUsers(validUsers, mentionedBy) mentionableUsers <- prefApi.mentionableIds(existingUsers)
validNotifies = validUnblockedUsers.map(Notification.Notifies.apply) users <- filterNotBlockedByUsers(mentionableUsers.toList, mentionedBy)
} yield validNotifies } yield users.map(Notification.Notifies.apply)
} }
private def filterNotBlockedByUsers( private def filterNotBlockedByUsers(

View File

@ -540,6 +540,7 @@ val `youCanAlsoScrollOverTheBoardToMoveInTheGame` = new I18nKey("youCanAlsoScrol
val `scrollOverComputerVariationsToPreviewThem` = new I18nKey("scrollOverComputerVariationsToPreviewThem") val `scrollOverComputerVariationsToPreviewThem` = new I18nKey("scrollOverComputerVariationsToPreviewThem")
val `analysisShapesHowTo` = new I18nKey("analysisShapesHowTo") val `analysisShapesHowTo` = new I18nKey("analysisShapesHowTo")
val `letOtherPlayersMessageYou` = new I18nKey("letOtherPlayersMessageYou") val `letOtherPlayersMessageYou` = new I18nKey("letOtherPlayersMessageYou")
val `receiveForumNotifications` = new I18nKey("receiveForumNotifications")
val `shareYourInsightsData` = new I18nKey("shareYourInsightsData") val `shareYourInsightsData` = new I18nKey("shareYourInsightsData")
val `withNobody` = new I18nKey("withNobody") val `withNobody` = new I18nKey("withNobody")
val `withFriends` = new I18nKey("withFriends") val `withFriends` = new I18nKey("withFriends")

View File

@ -36,6 +36,7 @@ object JsonView {
"coordColor" -> p.coordColor, "coordColor" -> p.coordColor,
"submitMove" -> p.submitMove, "submitMove" -> p.submitMove,
"confirmResign" -> p.confirmResign, "confirmResign" -> p.confirmResign,
"mention" -> p.mention,
"insightShare" -> p.insightShare, "insightShare" -> p.insightShare,
"keyboardMove" -> p.keyboardMove, "keyboardMove" -> p.keyboardMove,
"zen" -> p.zen, "zen" -> p.zen,

View File

@ -32,6 +32,7 @@ case class Pref(
coordColor: Int, coordColor: Int,
submitMove: Int, submitMove: Int,
confirmResign: Int, confirmResign: Int,
mention: Boolean,
insightShare: Int, insightShare: Int,
keyboardMove: Int, keyboardMove: Int,
zen: Int, zen: Int,
@ -211,6 +212,8 @@ object Pref {
) )
} }
object Mention extends BooleanPref
object KeyboardMove extends BooleanPref object KeyboardMove extends BooleanPref
object RookCastle { object RookCastle {
@ -433,6 +436,7 @@ object Pref {
coordColor = Color.RANDOM, coordColor = Color.RANDOM,
submitMove = SubmitMove.CORRESPONDENCE_ONLY, submitMove = SubmitMove.CORRESPONDENCE_ONLY,
confirmResign = ConfirmResign.YES, confirmResign = ConfirmResign.YES,
mention = true,
insightShare = InsightShare.FRIENDS, insightShare = InsightShare.FRIENDS,
keyboardMove = KeyboardMove.NO, keyboardMove = KeyboardMove.NO,
zen = Zen.NO, zen = Zen.NO,

View File

@ -51,7 +51,7 @@ final class PrefApi(
def followable(userId: User.ID): Fu[Boolean] = def followable(userId: User.ID): Fu[Boolean] =
coll.primitiveOne[Boolean]($id(userId), "follow") map (_ | Pref.default.follow) coll.primitiveOne[Boolean]($id(userId), "follow") map (_ | Pref.default.follow)
def unfollowableIds(userIds: List[User.ID]): Fu[Set[User.ID]] = private def unfollowableIds(userIds: List[User.ID]): Fu[Set[User.ID]] =
coll.secondaryPreferred.distinctEasy[User.ID, Set]( coll.secondaryPreferred.distinctEasy[User.ID, Set](
"_id", "_id",
$inIds(userIds) ++ $doc("follow" -> false) $inIds(userIds) ++ $doc("follow" -> false)
@ -65,6 +65,15 @@ final class PrefApi(
userIds map followables.contains userIds map followables.contains
} }
private def unmentionableIds(userIds: Set[User.ID]): Fu[Set[User.ID]] =
coll.secondaryPreferred.distinctEasy[User.ID, Set](
"_id",
$inIds(userIds) ++ $doc("mention" -> false)
)
def mentionableIds(userIds: Set[User.ID]): Fu[Set[User.ID]] =
unmentionableIds(userIds) map userIds.diff
def setPref(pref: Pref): Funit = def setPref(pref: Pref): Funit =
coll.update.one($id(pref.id), pref, upsert = true).void >>- coll.update.one($id(pref.id), pref, upsert = true).void >>-
cache.put(pref.id, fuccess(pref.some)) cache.put(pref.id, fuccess(pref.some))

View File

@ -51,6 +51,7 @@ object PrefForm {
"challenge" -> checkedNumber(Pref.Challenge.choices), "challenge" -> checkedNumber(Pref.Challenge.choices),
"message" -> checkedNumber(Pref.Message.choices), "message" -> checkedNumber(Pref.Message.choices),
"studyInvite" -> optional(checkedNumber(Pref.StudyInvite.choices)), "studyInvite" -> optional(checkedNumber(Pref.StudyInvite.choices)),
"mention" -> booleanNumber,
"insightShare" -> numberIn(Set(0, 1, 2)) "insightShare" -> numberIn(Set(0, 1, 2))
)(PrefData.apply)(PrefData.unapply) )(PrefData.apply)(PrefData.unapply)
) )
@ -95,6 +96,7 @@ object PrefForm {
challenge: Int, challenge: Int,
message: Int, message: Int,
studyInvite: Option[Int], studyInvite: Option[Int],
mention: Int,
insightShare: Int insightShare: Int
) { ) {
@ -119,6 +121,7 @@ object PrefForm {
premove = behavior.premove == 1, premove = behavior.premove == 1,
animation = display.animation, animation = display.animation,
submitMove = behavior.submitMove, submitMove = behavior.submitMove,
mention = mention == 1,
insightShare = insightShare, insightShare = insightShare,
confirmResign = behavior.confirmResign, confirmResign = behavior.confirmResign,
captured = display.captured == 1, captured = display.captured == 1,
@ -167,6 +170,7 @@ object PrefForm {
challenge = pref.challenge, challenge = pref.challenge,
message = pref.message, message = pref.message,
studyInvite = pref.studyInvite.some, studyInvite = pref.studyInvite.some,
mention = if (pref.mention) 1 else 0,
insightShare = pref.insightShare insightShare = pref.insightShare
) )
} }

View File

@ -42,6 +42,7 @@ private object PrefHandlers {
coordColor = r.getD("coordColor", Pref.default.coordColor), coordColor = r.getD("coordColor", Pref.default.coordColor),
submitMove = r.getD("submitMove", Pref.default.submitMove), submitMove = r.getD("submitMove", Pref.default.submitMove),
confirmResign = r.getD("confirmResign", Pref.default.confirmResign), confirmResign = r.getD("confirmResign", Pref.default.confirmResign),
mention = r.getD("mention", Pref.default.mention),
insightShare = r.getD("insightShare", Pref.default.insightShare), insightShare = r.getD("insightShare", Pref.default.insightShare),
keyboardMove = r.getD("keyboardMove", Pref.default.keyboardMove), keyboardMove = r.getD("keyboardMove", Pref.default.keyboardMove),
zen = r.getD("zen", Pref.default.zen), zen = r.getD("zen", Pref.default.zen),
@ -85,6 +86,7 @@ private object PrefHandlers {
"coordColor" -> o.coordColor, "coordColor" -> o.coordColor,
"submitMove" -> o.submitMove, "submitMove" -> o.submitMove,
"confirmResign" -> o.confirmResign, "confirmResign" -> o.confirmResign,
"mention" -> o.mention,
"insightShare" -> o.insightShare, "insightShare" -> o.insightShare,
"keyboardMove" -> o.keyboardMove, "keyboardMove" -> o.keyboardMove,
"zen" -> o.zen, "zen" -> o.zen,

View File

@ -681,6 +681,7 @@ computer analysis, game chat and shareable URL.</string>
<string name="scrollOverComputerVariationsToPreviewThem">Scroll over computer variations to preview them.</string> <string name="scrollOverComputerVariationsToPreviewThem">Scroll over computer variations to preview them.</string>
<string name="analysisShapesHowTo">Press shift+click or right-click to draw circles and arrows on the board.</string> <string name="analysisShapesHowTo">Press shift+click or right-click to draw circles and arrows on the board.</string>
<string name="letOtherPlayersMessageYou">Let other players message you</string> <string name="letOtherPlayersMessageYou">Let other players message you</string>
<string name="receiveForumNotifications">Receive notifications when mentioned in the forum</string>
<string name="shareYourInsightsData">Share your chess insights data</string> <string name="shareYourInsightsData">Share your chess insights data</string>
<string name="withNobody">With nobody</string> <string name="withNobody">With nobody</string>
<string name="withFriends">With friends</string> <string name="withFriends">With friends</string>