mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-26 16:46:12 +01:00
feat: add downvoteVisibility setting, closes #12698
This commit is contained in:
@@ -137,7 +137,8 @@
|
|||||||
"sitemapTopics": 500,
|
"sitemapTopics": 500,
|
||||||
"maintenanceMode": 0,
|
"maintenanceMode": 0,
|
||||||
"maintenanceModeStatus": 503,
|
"maintenanceModeStatus": 503,
|
||||||
"voteVisibility": "privileged",
|
"upvoteVisibility": "all",
|
||||||
|
"downvoteVisibility": "privileged",
|
||||||
"maximumInvites": 0,
|
"maximumInvites": 0,
|
||||||
"username:disableEdit": 0,
|
"username:disableEdit": 0,
|
||||||
"email:disableEdit": 0,
|
"email:disableEdit": 0,
|
||||||
|
|||||||
@@ -2,10 +2,14 @@
|
|||||||
"reputation": "Reputation Settings",
|
"reputation": "Reputation Settings",
|
||||||
"disable": "Disable Reputation System",
|
"disable": "Disable Reputation System",
|
||||||
"disable-down-voting": "Disable Down Voting",
|
"disable-down-voting": "Disable Down Voting",
|
||||||
"vote-visibility": "Vote visibility",
|
"upvote-visibility": "Up Vote visibility",
|
||||||
"vote-visibility-all": "Everyone can see votes",
|
"upvote-visibility-all": "Everyone can see up votes",
|
||||||
"vote-visibility-loggedin": "Only logged in users can see votes",
|
"upvote-visibility-loggedin": "Only logged in users can see up votes",
|
||||||
"vote-visibility-privileged": "Only privileged users like admins & moderators can see votes",
|
"upvote-visibility-privileged": "Only privileged users like admins & moderators can see up votes",
|
||||||
|
"downvote-visibility": "Down Vote visibility",
|
||||||
|
"downvote-visibility-all": "Everyone can see down votes",
|
||||||
|
"downvote-visibility-loggedin": "Only logged in users can see down votes",
|
||||||
|
"downvote-visibility-privileged": "Only privileged users like admins & moderators can see down votes",
|
||||||
"thresholds": "Activity Thresholds",
|
"thresholds": "Activity Thresholds",
|
||||||
"min-rep-upvote": "Minimum reputation to upvote posts",
|
"min-rep-upvote": "Minimum reputation to upvote posts",
|
||||||
"upvotes-per-day": "Upvotes per day (set to 0 for unlimited upvotes)",
|
"upvotes-per-day": "Upvotes per day (set to 0 for unlimited upvotes)",
|
||||||
|
|||||||
@@ -382,7 +382,9 @@ get:
|
|||||||
type: number
|
type: number
|
||||||
downvote:disabled:
|
downvote:disabled:
|
||||||
type: number
|
type: number
|
||||||
voteVisibility:
|
upvoteVisibility:
|
||||||
|
type: string
|
||||||
|
downvoteVisibility:
|
||||||
type: string
|
type: string
|
||||||
feeds:disableRSS:
|
feeds:disableRSS:
|
||||||
type: number
|
type: number
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ get:
|
|||||||
type: number
|
type: number
|
||||||
downvoteCount:
|
downvoteCount:
|
||||||
type: number
|
type: number
|
||||||
|
showUpvotes:
|
||||||
|
type: boolean
|
||||||
showDownvotes:
|
showDownvotes:
|
||||||
type: boolean
|
type: boolean
|
||||||
upvoters:
|
upvoters:
|
||||||
|
|||||||
@@ -9,17 +9,24 @@ define('forum/topic/votes', [
|
|||||||
|
|
||||||
Votes.addVoteHandler = function () {
|
Votes.addVoteHandler = function () {
|
||||||
_showTooltip = {};
|
_showTooltip = {};
|
||||||
if (canSeeVotes()) {
|
if (canSeeUpVotes()) {
|
||||||
components.get('topic').on('mouseenter', '[data-pid] [component="post/vote-count"]', loadDataAndCreateTooltip);
|
components.get('topic').on('mouseenter', '[data-pid] [component="post/vote-count"]', loadDataAndCreateTooltip);
|
||||||
components.get('topic').on('mouseleave', '[data-pid] [component="post/vote-count"]', destroyTooltip);
|
components.get('topic').on('mouseleave', '[data-pid] [component="post/vote-count"]', destroyTooltip);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function canSeeVotes() {
|
function canSeeUpVotes() {
|
||||||
const { voteVisibility, privileges } = ajaxify.data;
|
const { upvoteVisibility, privileges } = ajaxify.data;
|
||||||
return privileges.isAdminOrMod ||
|
return privileges.isAdminOrMod ||
|
||||||
voteVisibility === 'all' ||
|
upvoteVisibility === 'all' ||
|
||||||
(voteVisibility === 'loggedin' && config.loggedIn);
|
(upvoteVisibility === 'loggedin' && config.loggedIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
function canSeeVotes() {
|
||||||
|
const { upvoteVisibility, downvoteVisibility, privileges } = ajaxify.data;
|
||||||
|
return privileges.isAdminOrMod ||
|
||||||
|
upvoteVisibility === 'all' || downvoteVisibility === 'all' ||
|
||||||
|
((upvoteVisibility === 'loggedin' || downvoteVisibility === 'loggedin') && config.loggedIn);
|
||||||
}
|
}
|
||||||
|
|
||||||
function destroyTooltip() {
|
function destroyTooltip() {
|
||||||
|
|||||||
@@ -314,12 +314,19 @@ postsAPI.getVoters = async function (caller, data) {
|
|||||||
}
|
}
|
||||||
const { pid } = data;
|
const { pid } = data;
|
||||||
const cid = await posts.getCidByPid(pid);
|
const cid = await posts.getCidByPid(pid);
|
||||||
if (!await canSeeVotes(caller.uid, cid)) {
|
const [canSeeUpvotes, canSeeDownvotes] = await Promise.all([
|
||||||
|
canSeeVotes(caller.uid, cid, 'upvoteVisibility'),
|
||||||
|
canSeeVotes(caller.uid, cid, 'downvoteVisibility'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!canSeeUpvotes && !canSeeDownvotes) {
|
||||||
throw new Error('[[error:no-privileges]]');
|
throw new Error('[[error:no-privileges]]');
|
||||||
}
|
}
|
||||||
const showDownvotes = !meta.config['downvote:disabled'];
|
const repSystemDisabled = meta.config['reputation:disabled'];
|
||||||
|
const showUpvotes = canSeeUpvotes && !repSystemDisabled;
|
||||||
|
const showDownvotes = canSeeDownvotes && !meta.config['downvote:disabled'] && !repSystemDisabled;
|
||||||
const [upvoteUids, downvoteUids] = await Promise.all([
|
const [upvoteUids, downvoteUids] = await Promise.all([
|
||||||
db.getSetMembers(`pid:${data.pid}:upvote`),
|
showUpvotes ? db.getSetMembers(`pid:${data.pid}:upvote`) : [],
|
||||||
showDownvotes ? db.getSetMembers(`pid:${data.pid}:downvote`) : [],
|
showDownvotes ? db.getSetMembers(`pid:${data.pid}:downvote`) : [],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -331,6 +338,7 @@ postsAPI.getVoters = async function (caller, data) {
|
|||||||
return {
|
return {
|
||||||
upvoteCount: upvoters.length,
|
upvoteCount: upvoters.length,
|
||||||
downvoteCount: downvoters.length,
|
downvoteCount: downvoters.length,
|
||||||
|
showUpvotes: showUpvotes,
|
||||||
showDownvotes: showDownvotes,
|
showDownvotes: showDownvotes,
|
||||||
upvoters: upvoters,
|
upvoters: upvoters,
|
||||||
downvoters: downvoters,
|
downvoters: downvoters,
|
||||||
@@ -343,7 +351,7 @@ postsAPI.getUpvoters = async function (caller, data) {
|
|||||||
}
|
}
|
||||||
const { pid } = data;
|
const { pid } = data;
|
||||||
const cid = await posts.getCidByPid(pid);
|
const cid = await posts.getCidByPid(pid);
|
||||||
if (!await canSeeVotes(caller.uid, cid)) {
|
if (!await canSeeVotes(caller.uid, cid, 'upvoteVisibility')) {
|
||||||
throw new Error('[[error:no-privileges]]');
|
throw new Error('[[error:no-privileges]]');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,7 +378,7 @@ postsAPI.getUpvoters = async function (caller, data) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
async function canSeeVotes(uid, cids) {
|
async function canSeeVotes(uid, cids, type) {
|
||||||
const isArray = Array.isArray(cids);
|
const isArray = Array.isArray(cids);
|
||||||
if (!isArray) {
|
if (!isArray) {
|
||||||
cids = [cids];
|
cids = [cids];
|
||||||
@@ -389,8 +397,8 @@ async function canSeeVotes(uid, cids) {
|
|||||||
(
|
(
|
||||||
cidToAllowed[cid] &&
|
cidToAllowed[cid] &&
|
||||||
(
|
(
|
||||||
meta.config.voteVisibility === 'all' ||
|
meta.config[type] === 'all' ||
|
||||||
(meta.config.voteVisibility === 'loggedin' && parseInt(uid, 10) > 0)
|
(meta.config[type] === 'loggedin' && parseInt(uid, 10) > 0)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ topicsController.get = async function getTopic(req, res, next) {
|
|||||||
topicData.topicStaleDays = meta.config.topicStaleDays;
|
topicData.topicStaleDays = meta.config.topicStaleDays;
|
||||||
topicData['reputation:disabled'] = meta.config['reputation:disabled'];
|
topicData['reputation:disabled'] = meta.config['reputation:disabled'];
|
||||||
topicData['downvote:disabled'] = meta.config['downvote:disabled'];
|
topicData['downvote:disabled'] = meta.config['downvote:disabled'];
|
||||||
topicData.voteVisibility = meta.config.voteVisibility;
|
topicData.upvoteVisibility = meta.config.upvoteVisibility;
|
||||||
|
topicData.downvoteVisibility = meta.config.downvoteVisibility;
|
||||||
topicData['feeds:disableRSS'] = meta.config['feeds:disableRSS'] || 0;
|
topicData['feeds:disableRSS'] = meta.config['feeds:disableRSS'] || 0;
|
||||||
topicData['signatures:hideDuplicates'] = meta.config['signatures:hideDuplicates'];
|
topicData['signatures:hideDuplicates'] = meta.config['signatures:hideDuplicates'];
|
||||||
topicData.bookmarkThreshold = meta.config.bookmarkThreshold;
|
topicData.bookmarkThreshold = meta.config.bookmarkThreshold;
|
||||||
|
|||||||
20
src/upgrades/3.8.4/downvote-visibility-config.js
Normal file
20
src/upgrades/3.8.4/downvote-visibility-config.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const db = require('../../database');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'Add downvote visibility config field',
|
||||||
|
timestamp: Date.UTC(2024, 6, 17),
|
||||||
|
method: async function () {
|
||||||
|
const current = await db.getObjectField('config', 'voteVisibility');
|
||||||
|
if (current) {
|
||||||
|
await db.setObject('config', {
|
||||||
|
upvoteVisibility: current,
|
||||||
|
downvoteVisibility: current,
|
||||||
|
});
|
||||||
|
await db.deleteObjectField('config', 'voteVisibility');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -14,12 +14,20 @@
|
|||||||
<input type="checkbox" class="form-check-input" id="downvote:disabled" data-field="downvote:disabled">
|
<input type="checkbox" class="form-check-input" id="downvote:disabled" data-field="downvote:disabled">
|
||||||
<label for="downvote:disabled" class="form-check-label">[[admin/settings/reputation:disable-down-voting]]</label>
|
<label for="downvote:disabled" class="form-check-label">[[admin/settings/reputation:disable-down-voting]]</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="upvoteVisibility" class="form-check-label">[[admin/settings/reputation:upvote-visibility]]</label>
|
||||||
|
<select id="upvoteVisibility" data-field="upvoteVisibility" class="form-select">
|
||||||
|
<option value="all">[[admin/settings/reputation:upvote-visibility-all]]</option>
|
||||||
|
<option value="loggedin">[[admin/settings/reputation:upvote-visibility-loggedin]]</option>
|
||||||
|
<option value="privileged">[[admin/settings/reputation:upvote-visibility-privileged]]</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="voteVisibility" class="form-check-label">[[admin/settings/reputation:vote-visibility]]</label>
|
<label for="downvoteVisibility" class="form-check-label">[[admin/settings/reputation:downvote-visibility]]</label>
|
||||||
<select id="voteVisibility" data-field="voteVisibility" class="form-select">
|
<select id="downvoteVisibility" data-field="downvoteVisibility" class="form-select">
|
||||||
<option value="all">[[admin/settings/reputation:vote-visibility-all]]</option>
|
<option value="all">[[admin/settings/reputation:downvote-visibility-all]]</option>
|
||||||
<option value="loggedin">[[admin/settings/reputation:vote-visibility-loggedin]]</option>
|
<option value="loggedin">[[admin/settings/reputation:downvote-visibility-loggedin]]</option>
|
||||||
<option value="privileged">[[admin/settings/reputation:vote-visibility-privileged]]</option>
|
<option value="privileged">[[admin/settings/reputation:downvote-visibility-privileged]]</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
{{{ if showUpvotes }}}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<h4>[[global:upvoters]] <small>({upvoteCount})</small></h4>
|
<h4>[[global:upvoters]] <small>({upvoteCount})</small></h4>
|
||||||
{{{ each upvoters }}}
|
{{{ each upvoters }}}
|
||||||
<a class="text-decoration-none" href="{config.relative_path}/user/{./userslug}">{buildAvatar(@value, "24px", true)}</a>
|
<a class="text-decoration-none" href="{config.relative_path}/user/{./userslug}">{buildAvatar(@value, "24px", true)}</a>
|
||||||
{{{ end }}}
|
{{{ end }}}
|
||||||
</div>
|
</div>
|
||||||
|
{{{ end }}}
|
||||||
{{{ if showDownvotes }}}
|
{{{ if showDownvotes }}}
|
||||||
<div>
|
<div>
|
||||||
<h4>[[global:downvoters]] <small>({downvoteCount})</small></h4>
|
<h4>[[global:downvoters]] <small>({downvoteCount})</small></h4>
|
||||||
|
|||||||
Reference in New Issue
Block a user