Skip to content

Commit

Permalink
refactor Flag.validate()
Browse files Browse the repository at this point in the history
  • Loading branch information
tu2463 committed Sep 21, 2024
1 parent 03aed02 commit 99ebdc0
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 6 deletions.
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"extends": "nodebb"
"extends": "nodebb",
"parserOptions": {
"ecmaVersion": 2020 // This change in configuration is suggested by Copilot
}
}
2 changes: 1 addition & 1 deletion .mocharc.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
reporter: dot
timeout: 25000
exit: true
bail: true
bail: false
Binary file added dump.rdb
Binary file not shown.
125 changes: 125 additions & 0 deletions nodebb-theme-mytheme/topic.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<!-- IMPORT partials/breadcrumbs-json-ld.tpl -->
{{{ if config.theme.enableBreadcrumbs }}}
<!-- IMPORT partials/breadcrumbs.tpl -->
{{{ end }}}
{{{ if widgets.header.length }}}
<div data-widget-area="header">
{{{each widgets.header}}}
{{widgets.header.html}}
{{{end}}}
</div>
{{{ end }}}

<div itemid="{url}" itemscope itemtype="https://schema.org/DiscussionForumPosting">
<meta itemprop="headline" content="{escape(titleRaw)}">
<meta itemprop="text" content="{escape(titleRaw)}">
<meta itemprop="url" content="{url}">
<meta itemprop="datePublished" content="{timestampISO}">
<meta itemprop="dateModified" content="{lastposttimeISO}">
<div itemprop="author" itemscope itemtype="https://schema.org/Person">
<meta itemprop="name" content="{author.username}">
{{{ if author.userslug }}}<meta itemprop="url" content="{config.relative_path}/user/{author.userslug}">{{{ end }}}
</div>

<h1>Hahahahaha</h1>

<div class="d-flex flex-column gap-3">
<div class="d-flex flex-wrap">
<div class="d-flex flex-column gap-3 flex-grow-1">
<h1 component="post/header" class="tracking-tight fw-semibold fs-3 mb-0 text-break {{{ if config.theme.centerHeaderElements }}}text-center{{{ end }}}">
<span class="topic-title" component="topic/title">{title}</span>
</h1>

<div class="topic-info d-flex gap-2 align-items-center flex-wrap {{{ if config.theme.centerHeaderElements }}}justify-content-center{{{ end }}}">
<span component="topic/labels" class="d-flex gap-2 {{{ if (!scheduled && (!pinned && (!locked && (!oldCid && !icons.length)))) }}}hidden{{{ end }}}">
<span component="topic/scheduled" class="badge badge border border-gray-300 text-body {{{ if !scheduled }}}hidden{{{ end }}}">
<i class="fa fa-clock-o"></i> [[topic:scheduled]]
</span>
<span component="topic/pinned" class="badge badge border border-gray-300 text-body {{{ if (scheduled || !pinned) }}}hidden{{{ end }}}">
<i class="fa fa-thumb-tack"></i> {{{ if !pinExpiry }}}[[topic:pinned]]{{{ else }}}[[topic:pinned-with-expiry, {isoTimeToLocaleString(./pinExpiryISO, config.userLang)}]]{{{ end }}}
</span>
<span component="topic/locked" class="badge badge border border-gray-300 text-body {{{ if !locked }}}hidden{{{ end }}}">
<i class="fa fa-lock"></i> [[topic:locked]]
</span>
<a component="topic/moved" href="{config.relative_path}/category/{oldCid}" class="badge badge border border-gray-300 text-body text-decoration-none {{{ if !oldCid }}}hidden{{{ end }}}">
<i class="fa fa-arrow-circle-right"></i> {{{ if privileges.isAdminOrMod }}}[[topic:moved-from, {oldCategory.name}]]{{{ else }}}[[topic:moved]]{{{ end }}}
</a>
{{{each icons}}}<span class="lh-1">{@value}</span>{{{end}}}
</span>
{function.buildCategoryLabel, category, "a", "border"}
<div data-tid="{./tid}" component="topic/tags" class="lh-1 tags tag-list d-flex flex-wrap hidden-xs hidden-empty gap-2"><!-- IMPORT partials/topic/tags.tpl --></div>
<div class="d-flex hidden-xs gap-2"><!-- IMPORT partials/topic/stats.tpl --></div>
</div>
</div>
<div class="d-flex gap-2 justify-content-end align-items-center mt-2 hidden-empty" component="topic/thumb/list"><!-- IMPORT partials/topic/thumbs.tpl --></div>
</div>

<div class="row mb-4 mb-lg-0">
<div class="topic {{{ if widgets.sidebar.length }}}col-lg-9 col-sm-12{{{ else }}}col-lg-12{{{ end }}}">
<!-- IMPORT partials/post_bar.tpl -->
{{{ if merger }}}
<!-- IMPORT partials/topic/merged-message.tpl -->
{{{ end }}}
{{{ if forker }}}
<!-- IMPORT partials/topic/forked-message.tpl -->
{{{ end }}}
{{{ if !scheduled }}}
<!-- IMPORT partials/topic/deleted-message.tpl -->
{{{ end }}}

<div class="d-flex gap-0 gap-lg-5">
<div class="posts-container" style="min-width: 0;">
<ul component="topic" class="posts timeline list-unstyled mt-sm-2 p-0 py-3" style="min-width: 0;" data-tid="{tid}" data-cid="{cid}">
{{{ each posts }}}
<li component="post" class="pt-4 {{{ if posts.deleted }}}deleted{{{ end }}} {{{ if posts.selfPost }}}self-post{{{ end }}} {{{ if posts.topicOwnerPost }}}topic-owner-post{{{ end }}}" <!-- IMPORT partials/data/topic.tpl -->>
<a component="post/anchor" data-index="{./index}" id="{increment(./index, "1")}"></a>
<meta itemprop="datePublished" content="{./timestampISO}">
{{{ if ./editedISO }}}
<meta itemprop="dateModified" content="{./editedISO}">
{{{ end }}}

<!-- IMPORT partials/topic/post.tpl -->
</li>
{{{ if (config.topicPostSort != "most_votes") }}}
{{{ each ./events}}}<!-- IMPORT partials/topic/event.tpl -->{{{ end }}}
{{{ end }}}
{{{ end }}}
</ul>
{{{ if browsingUsers }}}
<div class="visible-xs">
<!-- IMPORT partials/topic/browsing-users.tpl -->
<hr/>
</div>
{{{ end }}}
{{{ if config.theme.enableQuickReply }}}
<!-- IMPORT partials/topic/quickreply.tpl -->
{{{ end }}}
</div>

<!-- IMPORT partials/topic/navigator.tpl -->
</div>

{{{ if config.usePagination }}}
<!-- IMPORT partials/paginator.tpl -->
{{{ end }}}
</div>
<div data-widget-area="sidebar" class="col-lg-3 col-sm-12 {{{ if !widgets.sidebar.length }}}hidden{{{ end }}}">
{{{each widgets.sidebar}}}
{{widgets.sidebar.html}}
{{{end}}}
</div>
</div>
</div>
</div>

<div data-widget-area="footer">
{{{each widgets.footer}}}
{{widgets.footer.html}}
{{{end}}}
</div>

{{{ if !config.usePagination }}}
<noscript>
<!-- IMPORT partials/paginator.tpl -->
</noscript>
{{{ end }}}
13 changes: 9 additions & 4 deletions src/flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,13 @@ Flags.sort = async function (flagIds, sort) {
return flagIds;
};

function checkSelfFlagError(payload) {
console.log('CHEYU TU - checkSelfFlagError');
if (parseInt(payload.id, 10) === parseInt(payload.uid, 10)) {
throw new Error('[[error:cant-flag-self]]');
}
}

Flags.validate = async function (payload) {
const [target, reporter] = await Promise.all([
Flags.getTarget(payload.type, payload.id, payload.uid),
Expand All @@ -283,7 +290,7 @@ Flags.validate = async function (payload) {
throw new Error('[[error:invalid-data]]');
} else if (target.deleted) {
throw new Error('[[error:post-deleted]]');
} else if (!reporter || !reporter.userslug) {
} else if (!reporter?.userslug) {
throw new Error('[[error:no-user]]');
} else if (reporter.banned) {
throw new Error('[[error:user-banned]]');
Expand All @@ -304,9 +311,7 @@ Flags.validate = async function (payload) {
throw new Error(`[[error:not-enough-reputation-to-flag, ${meta.config['min:rep:flag']}]]`);
}
} else if (payload.type === 'user') {
if (parseInt(payload.id, 10) === parseInt(payload.uid, 10)) {
throw new Error('[[error:cant-flag-self]]');
}
checkSelfFlagError(payload);
const editable = await privileges.users.canEdit(payload.uid, payload.id);
if (!editable && !meta.config['reputation:disabled'] && reporter.reputation < meta.config['min:rep:flag']) {
throw new Error(`[[error:not-enough-reputation-to-flag, ${meta.config['min:rep:flag']}]]`);
Expand Down
31 changes: 31 additions & 0 deletions test/flags.js
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,37 @@ describe('Flags', () => {
done();
});
});

function validateUserFlag(done) {
Flags.validate({
type: 'user',
id: 1,
uid: 3,
}, (err) => {
assert.ok(err);
assert.strictEqual('[[error:not-enough-reputation-to-flag, 50]]', err.message);
Meta.configs.set('min:rep:flag', 0, done);
});
}

it('should not pass validation if type is user, flag threshold is set and user rep does not meet it', (done) => {
Meta.configs.set('min:rep:flag', '50', (err) => {
assert.ifError(err);
validateUserFlag(done);
});
});

it('should throw an error if user tries to flag themselves', (done) => {
Flags.validate({
type: 'user',
id: 1,
uid: 1,
}, (err) => {
assert.ok(err);
assert.strictEqual('[[error:cant-flag-self]]', err.message);
done();
});
});
});

describe('.appendNote()', () => {
Expand Down

0 comments on commit 99ebdc0

Please sign in to comment.