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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user