mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-14 21:27:23 +01:00
Slur swear blocker challenges redux (#15089)
* update packages on local/origin repo * feat(challenges): add banned words & slur blocker to challenges * feat(challenges): slur blocker work * feat(challenges): slur blocker * feat(challenges): more slur blocker * feat(challenges): even more slur blocker * feat(challenges): swear and slur blocker * feat(challenges): update behavior based on public/private groups * feat(profiles): slur/swear blocker * feat(profiles): slur/swear blocker * feat(profiles/PMs): slur/swear blocker upgrade * feat(slur/swear): working on it * feat(profiles/challenges): work on profile block & slack report * feat(slur/swear blocker): work on Profiles * feat(slur blocker): refactoring code * feat(slur blocker): more refactoring * feat(slur blocker): arghhhhhh * fix(profiles): improve profanity check logic * fix(slack): update Slack notification to include authorEmail and remove undefined * feat(s/s blocker): work on challenges * feat(s/s blocker): challenge update * feat(s/s blocker): slack notifs refinements * feat(s/s blocker): refine slack notifs & disallow use of challenges POST API route if user is chatRevoked:true in db * update package.json and package-lock.json * attempt to disable create challenge button for muted users * another attempt to disable create challenge * block muted users from creating challenges * CSS button fun * fix CSS button * refactor(css): move button style to global Also, disable Clone button if user is chat revoked * fix(lint): remove unused fn * fix(challenges): handle null slur check * fix(groups): throw notFound earlier * fix(challenges): CSS and logic updates * fix(lint): remove whitespace * fix(challenges): don't disable create buttons * fix(slack): restore broken profile flag fields * chore(cleanup): remove comments and whitespace * chore(cleanup): one more white space --------- Co-authored-by: SabreCat <sabe@habitica.com>
This commit is contained in:
20
package-lock.json
generated
20
package-lock.json
generated
@@ -2542,7 +2542,7 @@
|
||||
"@types/json5": {
|
||||
"version": "0.0.29",
|
||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="
|
||||
"integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4="
|
||||
},
|
||||
"@types/jsonwebtoken": {
|
||||
"version": "8.5.9",
|
||||
@@ -4825,7 +4825,7 @@
|
||||
"bin-pack": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/bin-pack/-/bin-pack-1.0.2.tgz",
|
||||
"integrity": "sha512-aOk0SxEon5LF9cMxQFViSKb4qccG6rs7XKyMXIb1J8f8LA2acTIWnHdT0IOTe4gYBbqgjdbuTZ5f+UP+vlh4Mw=="
|
||||
"integrity": "sha1-wqAU7b8L7XCjKSBi7UZXe5YSBnk="
|
||||
},
|
||||
"bin-version": {
|
||||
"version": "3.1.0",
|
||||
@@ -10261,7 +10261,7 @@
|
||||
"ignore-by-default": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
|
||||
"integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk="
|
||||
"integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA=="
|
||||
},
|
||||
"image-size": {
|
||||
"version": "1.0.2",
|
||||
@@ -11691,7 +11691,7 @@
|
||||
"lodash.get": {
|
||||
"version": "4.4.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
|
||||
"integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==",
|
||||
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
|
||||
"dev": true
|
||||
},
|
||||
"lodash.includes": {
|
||||
@@ -12777,7 +12777,7 @@
|
||||
"ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -13144,7 +13144,7 @@
|
||||
"nopt": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
||||
"integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
|
||||
"integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==",
|
||||
"requires": {
|
||||
"abbrev": "1"
|
||||
}
|
||||
@@ -14209,7 +14209,7 @@
|
||||
"pause": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
|
||||
"integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
|
||||
"integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg=="
|
||||
},
|
||||
"pause-stream": {
|
||||
"version": "0.0.11",
|
||||
@@ -15363,7 +15363,7 @@
|
||||
"secure-keys": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz",
|
||||
"integrity": "sha1-8MgtmKOxOah3aogIBQuCRDEIf8o="
|
||||
"integrity": "sha512-nZi59hW3Sl5P3+wOO89eHBAAGwmCPd2aE1+dLZV5MO+ItQctIvAqihzaAXIQhvtH4KJPxM080HsnqltR2y8cWg=="
|
||||
},
|
||||
"seek-bzip": {
|
||||
"version": "1.0.5",
|
||||
@@ -15755,7 +15755,7 @@
|
||||
"sliced": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
|
||||
"integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
|
||||
"integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA=="
|
||||
},
|
||||
"snapdragon": {
|
||||
"version": "0.8.2",
|
||||
@@ -16445,7 +16445,7 @@
|
||||
"strip-bom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="
|
||||
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
|
||||
},
|
||||
"strip-bom-stream": {
|
||||
"version": "1.0.0",
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
"client:unit": "cd website/client && npm run test:unit",
|
||||
"start": "gulp nodemon",
|
||||
"debug": "gulp nodemon --inspect",
|
||||
"mongo:dev": "run-rs -v 4.1.1 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet",
|
||||
"mongo:dev": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet",
|
||||
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
|
||||
"apidoc": "gulp apidoc"
|
||||
},
|
||||
|
||||
2
website/client/package-lock.json
generated
2
website/client/package-lock.json
generated
@@ -18076,7 +18076,7 @@
|
||||
"strip-bom": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
|
||||
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="
|
||||
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
|
||||
},
|
||||
"strip-eof": {
|
||||
"version": "1.0.0",
|
||||
|
||||
@@ -28,7 +28,15 @@
|
||||
|
||||
&:disabled, &.disabled {
|
||||
cursor: default;
|
||||
color: $gray-50;
|
||||
opacity: 0.75;
|
||||
box-shadow: 0 1px 3px 0 rgba(26, 24, 29, 0.12), 0 1px 2px 0 rgba(26, 24, 29, 0.24);
|
||||
background-color: $gray-700;
|
||||
border: 1px solid transparent;
|
||||
|
||||
.svg {
|
||||
color: $gray-300;
|
||||
}
|
||||
}
|
||||
|
||||
&.with-icon {
|
||||
@@ -77,16 +85,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled, &.disabled {
|
||||
background: $gray-700;
|
||||
border: 1px solid transparent;
|
||||
cursor: default;
|
||||
color: $gray-50;
|
||||
|
||||
--icon-color: #{$gray-300};
|
||||
}
|
||||
|
||||
|
||||
&.with-icon {
|
||||
.svg-icon.color {
|
||||
color: var(--icon-color);
|
||||
@@ -134,19 +132,12 @@
|
||||
border: 1px solid transparent;
|
||||
|
||||
--icon-color: #{$purple-300};
|
||||
.svg {
|
||||
color: $purple-300;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled, &.disabled {
|
||||
color: $gray-50;
|
||||
background: $white;
|
||||
border: 1px solid transparent;
|
||||
cursor: default;
|
||||
opacity: 0.75;
|
||||
|
||||
--icon-color: #{$gray-300};
|
||||
}
|
||||
|
||||
&.with-icon {
|
||||
.svg-icon.color {
|
||||
color: var(--icon-color);
|
||||
@@ -181,13 +172,6 @@
|
||||
background: $maroon-100;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
&:disabled, &.disabled {
|
||||
background: $maroon-100;
|
||||
border: 1px solid transparent;
|
||||
cursor: default;
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
@@ -213,13 +197,6 @@
|
||||
background: $green-50;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
&:disabled, &.disabled {
|
||||
background: $green-50;
|
||||
border: 1px solid transparent;
|
||||
cursor: default;
|
||||
opacity: 0.75;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
|
||||
@@ -189,8 +189,9 @@
|
||||
<div>
|
||||
<button
|
||||
class="btn"
|
||||
:disabled="flaggedAndHidden"
|
||||
:class="flaggedAndHidden ? 'disabled btn-disabled' : 'btn-primary'"
|
||||
:disabled="flaggedAndHidden || chatRevocation"
|
||||
:class="flaggedAndHidden || chatRevocation
|
||||
? 'disabled btn-disabled' : 'btn-primary'"
|
||||
@click="cloneChallenge()"
|
||||
>
|
||||
{{ $t('clone') }}
|
||||
@@ -280,17 +281,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.btn-disabled {
|
||||
background-color: $gray-700;
|
||||
color: $gray-50;
|
||||
box-shadow: none;
|
||||
cursor: arrow;
|
||||
|
||||
&:hover {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-icon {
|
||||
width: 12px;
|
||||
display: inline-block;
|
||||
@@ -473,6 +463,10 @@ export default {
|
||||
flaggedAndHidden () {
|
||||
return this.challenge.flagCount > 1;
|
||||
},
|
||||
chatRevocation () {
|
||||
return this.user.flags.chatRevoked
|
||||
&& this.challenge.group && this.challenge.group.name === 'Tavern';
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
'challenge.name': {
|
||||
|
||||
@@ -433,10 +433,12 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
this.groups.push({
|
||||
name: this.$t('publicChallengesTitle'),
|
||||
_id: TAVERN_ID,
|
||||
});
|
||||
if (!this.user.flags.chatRevoked) {
|
||||
this.groups.push({
|
||||
name: this.$t('publicChallengesTitle'),
|
||||
_id: TAVERN_ID,
|
||||
});
|
||||
}
|
||||
|
||||
this.setUpWorkingChallenge();
|
||||
},
|
||||
|
||||
@@ -13,16 +13,12 @@
|
||||
</h1>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<!-- @TODO: implement sorting span.dropdown-label
|
||||
{{ $t('sortBy') }}b-dropdown(:text="$t('sort')", right=true)
|
||||
b-dropdown-item(v-for='sortOption in sortOptions',
|
||||
:key="sortOption.value", @click='sort(sortOption.value)') {{sortOption.text}}-->
|
||||
<button
|
||||
class="btn btn-secondary create-challenge-button float-right"
|
||||
@click="createChallenge()"
|
||||
>
|
||||
<div
|
||||
class="svg-icon positive-icon"
|
||||
class="svg svg-icon positive-icon color"
|
||||
v-html="icons.positiveIcon"
|
||||
></div>
|
||||
<span v-once>{{ $t('createChallenge') }}</span>
|
||||
@@ -87,13 +83,16 @@
|
||||
|
||||
.create-challenge-button {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.positive-icon {
|
||||
color: $green-10;
|
||||
width: 10px;
|
||||
display: inline-block;
|
||||
margin-right: .5em;
|
||||
&:not(.disabled) .svg {
|
||||
color: $green-10;
|
||||
}
|
||||
|
||||
.positive-icon {
|
||||
width: 10px;
|
||||
display: inline-block;
|
||||
margin-right: .5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
@click="createChallenge()"
|
||||
>
|
||||
<div
|
||||
class="svg-icon positive-icon"
|
||||
class="svg svg-icon positive-icon color"
|
||||
v-html="icons.positiveIcon"
|
||||
></div>
|
||||
<span v-once>{{ $t('createChallenge') }}</span>
|
||||
@@ -106,13 +106,16 @@
|
||||
|
||||
.create-challenge-button {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.positive-icon {
|
||||
color: $green-10;
|
||||
width: 10px;
|
||||
display: inline-block;
|
||||
margin-right: .5em;
|
||||
&:not(.disabled) .svg {
|
||||
color: $green-10;
|
||||
}
|
||||
|
||||
.positive-icon {
|
||||
width: 10px;
|
||||
display: inline-block;
|
||||
margin-right: .5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
<button
|
||||
class="btn btn-primary send-chat float-right"
|
||||
:disabled="!communityGuidelinesAccepted"
|
||||
:class="{ disabled: !communityGuidelinesAccepted }"
|
||||
@click="sendMessage()"
|
||||
>
|
||||
{{ $t('send') }}
|
||||
|
||||
@@ -106,5 +106,6 @@
|
||||
"abuseFlagModalBodyChallenge": "You should only report a Challenge that violates the <%= firstLinkStart %>Community Guidelines<%= linkEnd %> and/or <%= secondLinkStart %>Terms of Service<%= linkEnd %>. Submitting a false report is a violation of Habitica's Community Guidelines.",
|
||||
"cannotClose": "This Challenge cannot be closed because one or more players have reported it as inappropriate. A staff members will contact you shortly with instructions. If over 48 hours have passed and you have not heard from them, please email admin@habitica.com for assistance.",
|
||||
"cannotClone": "This Challenge cannot be cloned because one or more players have reported it as inappropriate. A staff member will contact you shortly with instructions. If over 48 hours have passed and you have not heard from them, please email admin@habitica.com for assistance.",
|
||||
"resetFlags": "Reset Flags"
|
||||
"resetFlags": "Reset Flags",
|
||||
"cannotMakeChallenge": "You are unable to create public Challenges as your account currently does not have chat privileges. Please contact admin@habitica.com for more information."
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
"communityGuidelines": "Community Guidelines",
|
||||
"bannedWordUsed": "Oops! Looks like this post contains a swear word or reference to an addictive substance or adult topic (<%= swearWordsUsed %>). Habitica keeps our chat very clean. Feel free to edit your message so you can post it! You must remove the word, not just censor it.",
|
||||
"bannedSlurUsed": "Your post contained inappropriate language, and your chat privileges have been revoked.",
|
||||
"challengeBannedSlurs": "Your Challenge contains a slur which violates Habitica’s community guidelines and your chat and Challenge creation privileges have been revoked. Contact admin@habitica.com for more information.",
|
||||
"challengeBannedWords": "Your Challenge contains one or more swear words or references to an adult topic. Please edit your Challenge so you can save it. You must remove the word, not just censor it.",
|
||||
"challengeBannedSlursPrivate": "Your Challenge contains a slur which violates Habitica's community guidelines. Please remove it in order to save your Challenge.",
|
||||
"party": "Party",
|
||||
"usernameCopied": "Username copied to clipboard.",
|
||||
"create": "Create",
|
||||
|
||||
@@ -2,6 +2,11 @@ import _ from 'lodash';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { authWithHeaders, authWithSession } from '../../middlewares/auth';
|
||||
import { model as Challenge } from '../../models/challenge';
|
||||
import bannedWords from '../../libs/bannedWords';
|
||||
import bannedSlurs from '../../libs/bannedSlurs';
|
||||
import { getMatchesByWordArray } from '../../libs/stringUtils';
|
||||
import * as slack from '../../libs/slack';
|
||||
import { getUserInfo } from '../../libs/email';
|
||||
import {
|
||||
model as Group,
|
||||
basicFields as basicGroupFields,
|
||||
@@ -12,6 +17,7 @@ import {
|
||||
nameFields,
|
||||
} from '../../models/user';
|
||||
import {
|
||||
BadRequest,
|
||||
NotFound,
|
||||
NotAuthorized,
|
||||
} from '../../libs/errors';
|
||||
@@ -39,6 +45,22 @@ const { MAX_SUMMARY_SIZE_FOR_CHALLENGES } = common.constants;
|
||||
|
||||
const api = {};
|
||||
|
||||
function textContainsBannedWord (message) {
|
||||
if (!message) {
|
||||
return false;
|
||||
}
|
||||
const bannedWordsMatched = getMatchesByWordArray(message, bannedWords);
|
||||
return bannedWordsMatched.length > 0;
|
||||
}
|
||||
|
||||
function textContainsBannedSlur (message) {
|
||||
if (!message) {
|
||||
return false;
|
||||
}
|
||||
const bannedSlursMatched = getMatchesByWordArray(message, bannedSlurs);
|
||||
return bannedSlursMatched.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @apiDefine ChallengeLeader Challenge Leader
|
||||
* The leader of the challenge can use this route.
|
||||
@@ -212,7 +234,50 @@ api.createChallenge = {
|
||||
const validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
|
||||
const { savedChal, group } = await createChallenge(user, req, res);
|
||||
const group = await Group.getGroup({
|
||||
user, groupId: req.body.group, fields: basicGroupFields, optionalMembership: true,
|
||||
});
|
||||
|
||||
if (!group) {
|
||||
throw new NotFound(res.t('groupNotFound'));
|
||||
}
|
||||
|
||||
// check public challenges for banned words & chat revocation
|
||||
if (group.privacy === 'public') {
|
||||
const textToCheck = `${req.body.name} ${req.body.shortName} ${req.body.summary} ${req.body.description}`;
|
||||
if (textContainsBannedSlur(textToCheck)) {
|
||||
const authorEmail = getUserInfo(user, ['email']).email;
|
||||
const problemContent = `Challenge Name: ${req.body.name}\n
|
||||
Challenge Tag: ${req.body.shortName}\n
|
||||
Challenge Summary: ${req.body.summary}\n
|
||||
Challenge Description: ${req.body.description}`;
|
||||
|
||||
slack.sendChallengeSlurNotification({
|
||||
authorEmail,
|
||||
author: user,
|
||||
displayName: user.profile.name,
|
||||
username: user.auth.local.username,
|
||||
uuid: user.id,
|
||||
language: user.preferences.language,
|
||||
problemContent,
|
||||
});
|
||||
|
||||
user.flags.chatRevoked = true;
|
||||
await user.save();
|
||||
|
||||
throw new BadRequest(res.t('challengeBannedSlurs'));
|
||||
}
|
||||
if (textContainsBannedWord(textToCheck)) {
|
||||
throw new BadRequest(res.t('challengeBannedWords'));
|
||||
}
|
||||
if (user.flags.chatRevoked) {
|
||||
throw new BadRequest(res.t('cannotMakeChallenge'));
|
||||
}
|
||||
}
|
||||
|
||||
const { savedChal } = await createChallenge(user, req, res);
|
||||
|
||||
await user.save();
|
||||
|
||||
const response = savedChal.toJSON();
|
||||
response.leader = { // the leader is the authenticated user
|
||||
|
||||
@@ -358,6 +358,42 @@ function sendProfileSlurNotification ({
|
||||
.catch(err => logger.error(err, 'Error while sending flag data to Slack.'));
|
||||
}
|
||||
|
||||
function sendChallengeSlurNotification ({
|
||||
authorEmail,
|
||||
author,
|
||||
language,
|
||||
problemContent,
|
||||
uuid,
|
||||
}) {
|
||||
if (SKIP_FLAG_METHODS) {
|
||||
return;
|
||||
}
|
||||
const text = `${author.profile.name} ${authorEmail} (${uuid}, ${language}) tried to create a Challenge with a slur or banned word.`;
|
||||
|
||||
const authorName = formatUser({
|
||||
name: author.auth.local.username,
|
||||
displayName: author.profile.name,
|
||||
email: authorEmail,
|
||||
uuid: author.id,
|
||||
language,
|
||||
});
|
||||
|
||||
flagSlack
|
||||
.send({
|
||||
text,
|
||||
attachments: [{
|
||||
fallback: 'Slur Message',
|
||||
color: 'danger',
|
||||
author_name: authorName,
|
||||
text: problemContent,
|
||||
mrkdwn_in: [
|
||||
'text',
|
||||
],
|
||||
}],
|
||||
})
|
||||
.catch(err => logger.error(err, 'Error while sending flag data to Slack.'));
|
||||
}
|
||||
|
||||
export {
|
||||
sendFlagNotification,
|
||||
sendInboxFlagNotification,
|
||||
@@ -366,5 +402,6 @@ export {
|
||||
sendSubscriptionNotification,
|
||||
sendShadowMutedPostNotification,
|
||||
sendProfileSlurNotification,
|
||||
sendChallengeSlurNotification,
|
||||
formatUser,
|
||||
};
|
||||
|
||||
@@ -11,9 +11,7 @@ const bannedSlurRegexes = bannedSlurs.map(word => new RegExp(`\\b([^a-z]+)?${wor
|
||||
const bannedWordRegexes = bannedWords.map(word => new RegExp(`\\b([^a-z]+)?${word}([^a-z]+)?\\b`, 'i'));
|
||||
|
||||
export function stringContainsProfanity (str, profanityType = 'bannedWord') {
|
||||
const bannedRegexes = profanityType === 'slur'
|
||||
? bannedSlurRegexes
|
||||
: bannedWordRegexes;
|
||||
const bannedRegexes = profanityType === 'slur' ? bannedSlurRegexes : bannedWordRegexes;
|
||||
|
||||
for (let i = 0; i < bannedRegexes.length; i += 1) {
|
||||
const regEx = bannedRegexes[i];
|
||||
|
||||
Reference in New Issue
Block a user