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(),
radios(form("studyInvite"), translatedStudyInviteChoices)
),
setting(
trans.receiveForumNotifications(),
radios(form("mention"), booleanChoices)
),
setting(
trans.shareYourInsightsData(),
radios(form("insightShare"), translatedInsightShareChoices)

View File

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

View File

@ -4,6 +4,7 @@ import lila.common.Future
import lila.notify.NotifyApi
import lila.notify.{ MentionedInThread, Notification }
import lila.relation.RelationApi
import lila.pref.PrefApi
import lila.user.{ User, UserRepo }
/** Notifier to inform users if they have been mentioned in a post
@ -13,11 +14,10 @@ import lila.user.{ User, UserRepo }
final class MentionNotifier(
userRepo: UserRepo,
notifyApi: NotifyApi,
relationApi: RelationApi
relationApi: RelationApi,
prefApi: PrefApi
)(implicit ec: scala.concurrent.ExecutionContext) {
private val forbidden = Set("lichess", "thibault")
def notifyMentionedUsers(post: Post, topic: Topic): Funit =
post.userId.ifFalse(post.troll) ?? { author =>
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
* 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 {
validUsers <-
existingUsers <-
userRepo
.existingUsernameIds(users take 10 diff forbidden)
.map(_ take 5)
validUnblockedUsers <- filterNotBlockedByUsers(validUsers, mentionedBy)
validNotifies = validUnblockedUsers.map(Notification.Notifies.apply)
} yield validNotifies
.existingUsernameIds(candidates take 10)
.map(_.take(5).toSet)
mentionableUsers <- prefApi.mentionableIds(existingUsers)
users <- filterNotBlockedByUsers(mentionableUsers.toList, mentionedBy)
} yield users.map(Notification.Notifies.apply)
}
private def filterNotBlockedByUsers(

View File

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

View File

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

View File

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

View File

@ -51,7 +51,7 @@ final class PrefApi(
def followable(userId: User.ID): Fu[Boolean] =
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](
"_id",
$inIds(userIds) ++ $doc("follow" -> false)
@ -65,6 +65,15 @@ final class PrefApi(
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 =
coll.update.one($id(pref.id), pref, upsert = true).void >>-
cache.put(pref.id, fuccess(pref.some))

View File

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

View File

@ -42,6 +42,7 @@ private object PrefHandlers {
coordColor = r.getD("coordColor", Pref.default.coordColor),
submitMove = r.getD("submitMove", Pref.default.submitMove),
confirmResign = r.getD("confirmResign", Pref.default.confirmResign),
mention = r.getD("mention", Pref.default.mention),
insightShare = r.getD("insightShare", Pref.default.insightShare),
keyboardMove = r.getD("keyboardMove", Pref.default.keyboardMove),
zen = r.getD("zen", Pref.default.zen),
@ -85,6 +86,7 @@ private object PrefHandlers {
"coordColor" -> o.coordColor,
"submitMove" -> o.submitMove,
"confirmResign" -> o.confirmResign,
"mention" -> o.mention,
"insightShare" -> o.insightShare,
"keyboardMove" -> o.keyboardMove,
"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="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="receiveForumNotifications">Receive notifications when mentioned in the forum</string>
<string name="shareYourInsightsData">Share your chess insights data</string>
<string name="withNobody">With nobody</string>
<string name="withFriends">With friends</string>