Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added feature that adds a flag icon to all replies that contain curse words #15

Merged
merged 13 commits into from
Feb 11, 2025
1 change: 1 addition & 0 deletions nodebb-theme-harmony/templates/partials/topic/post.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
<div class="d-flex align-items-center gap-1 flex-grow-1 justify-content-end">
<span class="bookmarked opacity-0 text-primary"><i class="fa fa-bookmark-o"></i></span>
<a href="{config.relative_path}/post/{./pid}" class="post-index text-muted d-none d-md-inline">#{increment(./index, "1")}</a>
{{{ if (posts.contentFlag == "true") }}} <i class="fas fa-flag" style="color:orange;"></i> {{{ end }}}
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
{{{ if privileges.topics:reply }}}
<div component="topic/reply/container" class="btn-group">
<a href="{config.relative_path}/compose?tid={tid}" class="d-flex align-items-center btn btn-sm btn-primary px-3 fw-semibold" component="topic/reply" data-ajaxify="false" role="button"><i class="fa fa-reply d-sm-block d-md-none"></i><span class="d-none d-md-block"> [[topic:reply]]</span></a>
<button type="button" class="btn btn-sm btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="[[topic:reply-options]]">
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-end p-1 text-sm" role="menu">
<li><a class="dropdown-item rounded-1" href="#" component="topic/reply-as-topic" role="menuitem">[[topic:reply-as-topic]]</a></li>
</ul>
</div>
{{{ end }}}

Expand Down
9 changes: 0 additions & 9 deletions public/src/client/topic/postTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,6 @@ define('forum/topic/postTools', [
onReplyClicked($(this), tid);
});

$('.topic').on('click', '[component="topic/reply-as-topic"]', function () {
translator.translate(`[[topic:link-back, ${ajaxify.data.titleRaw}, ${config.relative_path}/topic/${ajaxify.data.slug}]]`, function (body) {
hooks.fire('action:composer.topic.new', {
cid: ajaxify.data.cid,
body: body,
});
});
});

postContainer.on('click', '[component="post/bookmark"]', function () {
return bookmarkPost($(this), getData($(this), 'data-pid'));
});
Expand Down
3 changes: 3 additions & 0 deletions src/posts/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ module.exports = function (Posts) {
if (data.handle && !parseInt(uid, 10)) {
postData.handle = data.handle;
}
if (data.contentFlag) {
postData.contentFlag = data.contentFlag;
}

let result = await plugins.hooks.fire('filter:post.create', { post: postData, data: data });
postData = result.post;
Expand Down
2 changes: 2 additions & 0 deletions src/posts/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const pubsub = require('../pubsub');
const utils = require('../utils');
const slugify = require('../slugify');
const translator = require('../translator');
const flagContent = require('./flagContent');

module.exports = function (Posts) {
pubsub.on('post:edit', (pid) => {
Expand Down Expand Up @@ -195,6 +196,7 @@ module.exports = function (Posts) {
const editPostData = {
content: data.content,
editor: data.uid,
contentFlag: flagContent(data.content),
};

// For posts in scheduled topics, if edited before, use edit timestamp
Expand Down
10 changes: 10 additions & 0 deletions src/posts/flagContent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict';

// List of banned words (in hex)
const BANNED_WORDS = ['\x66\x75\x63\x6b', '\x73\x68\x69\x74', '\x61\x73\x73', '\x62\x69\x74\x63\x68', '\x63\x75\x6e\x74', '\x70\x75\x73\x73\x79', '\x6e\x69\x67\x67\x65\x72'];

// Splits a content string and checks if any of the words in it are in the banned words list
module.exports = function flagContent(content) {
const words = content.toLowerCase().split(' ');
return words.some(x => BANNED_WORDS.includes(x));
};
6 changes: 6 additions & 0 deletions src/topics/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const posts = require('../posts');
const privileges = require('../privileges');
const categories = require('../categories');
const translator = require('../translator');
const flagContent = require('../posts/flagContent');

module.exports = function (Topics) {
Topics.create = async function (data) {
Expand Down Expand Up @@ -193,6 +194,11 @@ module.exports = function (Topics) {
data.timestamp = topicData.lastposttime + 1;
}

// Add a flag to any content with banned words
if (flagContent(data.content)) {
data.contentFlag = true;
}

data.ip = data.req ? data.req.ip : null;
let postData = await posts.create(data);
postData = await onNewPost(postData, data);
Expand Down
10 changes: 10 additions & 0 deletions test/topics.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,16 @@ describe('Topic\'s', () => {

assert.equal(postData.length, 1, 'should have 1 result');
assert.equal(postData[0].pid, result.pid, 'result should be the reply we added');
assert.equal(postData[0].contentFlag, undefined, 'result should not have a content flag');
});

it('should add content flag', async () => {
const result = await topics.reply({ uid: topic.userId, content: 'test reply, fuck', tid: newTopic.tid, toPid: newPost.pid });
assert.ok(result);

const postData = await apiPosts.getReplies({ uid: 0 }, { pid: newPost.pid });
assert.ok(postData);
assert.equal(postData[1].contentFlag, 'true', 'result should have a content flag');
});

it('should error if pid is not a number', async () => {
Expand Down
Loading