diff --git a/modules/msg/src/main/MsgSecurity.scala b/modules/msg/src/main/MsgSecurity.scala index 274c455f63..c593d7ebb7 100644 --- a/modules/msg/src/main/MsgSecurity.scala +++ b/modules/msg/src/main/MsgSecurity.scala @@ -70,6 +70,7 @@ final private class MsgSecurity( case false => fuccess(Block) case _ => isLimited(contacts, isNew, unlimited) orElse + isFakeTeamMessage(rawText, unlimited) orElse isSpam(text) orElse isTroll(contacts) orElse isDirt(contacts.orig, text, isNew) getOrElse @@ -110,6 +111,10 @@ final private class MsgSecurity( ReplyLimitPerUser[Option[Verdict]](contacts.orig.id, limitCost(contacts.orig))(none)(Limit.some) } + private def isFakeTeamMessage(text: String, unlimited: Boolean): Fu[Option[Verdict]] = + (!unlimited && text.contains("You received this because you are subscribed to messages of the team")) ?? + fuccess(FakeTeamMessage.some) + private def isSpam(text: String): Fu[Option[Verdict]] = spam.detect(text) ?? fuccess(Spam.some) @@ -182,11 +187,12 @@ private object MsgSecurity { sealed abstract class Send(val mute: Boolean) extends Verdict sealed abstract class Mute extends Send(true) - case object Ok extends Send(false) - case object Troll extends Mute - case object Spam extends Mute - case object Dirt extends Mute - case object Block extends Reject - case object Limit extends Reject - case object Invalid extends Reject + case object Ok extends Send(false) + case object Troll extends Mute + case object Spam extends Mute + case object Dirt extends Mute + case object FakeTeamMessage extends Reject + case object Block extends Reject + case object Limit extends Reject + case object Invalid extends Reject } diff --git a/ui/msg/css/_convoMsgs.scss b/ui/msg/css/_convoMsgs.scss index a8cfa40fae..ddcd88c995 100644 --- a/ui/msg/css/_convoMsgs.scss +++ b/ui/msg/css/_convoMsgs.scss @@ -112,4 +112,11 @@ padding: 0; } } + + form.unsub { + display: inline; + .button { + text-transform: none; + } + } } diff --git a/ui/msg/src/view/enhance.ts b/ui/msg/src/view/enhance.ts index c53e6abe32..456b867ec6 100644 --- a/ui/msg/src/view/enhance.ts +++ b/ui/msg/src/view/enhance.ts @@ -5,6 +5,8 @@ export { isMoreThanText } from 'common/richText'; const imgurRegex = /https?:\/\/(?:i\.)?imgur\.com\/(\w+)(?:\.jpe?g|\.png|\.gif)?/; const giphyRegex = /https:\/\/(?:media\.giphy\.com\/media\/|giphy\.com\/gifs\/(?:\w+-)*)(\w+)(?:\/giphy\.gif)?/; +const teamMessageRegex = + /You received this because you are subscribed to messages of the team ]+)>(?:[^\/]+)(.+)<\/a>\.$/; const img = (src: string) => ``; @@ -35,8 +37,17 @@ const expandGameIds = (html: string) => (_: string, id: string, suffix: string) => ' ' + linkReplace('/' + id, '#' + id, 'text') + suffix ); +const expandTeamMessage = (html: string) => + html.replace( + teamMessageRegex, + (_: string, url: string) => + `${expandLink( + url + )}
` + ); + export const enhance = (str: string) => - expandGameIds(expandMentions(expandUrls(lichess.escapeHtml(str)))).replace(newLineRegex, '
'); + expandTeamMessage(expandGameIds(expandMentions(expandUrls(lichess.escapeHtml(str))))).replace(newLineRegex, '
'); /* Enhance with iframe expansion */ diff --git a/ui/msg/src/view/msgs.ts b/ui/msg/src/view/msgs.ts index f23baf1136..9b7519132d 100644 --- a/ui/msg/src/view/msgs.ts +++ b/ui/msg/src/view/msgs.ts @@ -1,6 +1,7 @@ import { h, VNode } from 'snabbdom'; import { Convo, Msg, Daily } from '../interfaces'; import * as enhance from './enhance'; +import * as xhr from 'common/xhr'; import { scroller } from './scroller'; import { bind } from './util'; import MsgCtrl from '../ctrl'; @@ -108,6 +109,10 @@ const renderText = (msg: Msg) => const el = vnode.elm as HTMLElement; el.innerHTML = enhance.enhance(msg.text); el.querySelectorAll('img').forEach(c => c.addEventListener('load', scroller.auto, { once: true })); + $('form.unsub', el).on('submit', function (this: HTMLFormElement) { + teamUnsub(this); + return false; + }); }, }, }) @@ -119,3 +124,13 @@ const setupMsgs = (insert: boolean) => (vnode: VNode) => { enhance.expandIFrames(el); scroller.toMarker() || scroller.auto(); }; + +const teamUnsub = (form: HTMLFormElement) => { + if (confirm('Unsubscribe?')) + xhr + .json(form.action, { + method: 'post', + body: xhr.form({ subscribe: false }), + }) + .then(() => alert('Done!')); +};