From 269fc06835b0d1afc0a90dedc16d32be78069315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Wed, 17 Jul 2024 17:43:31 -0400 Subject: [PATCH 1/3] feat: add downvoteVisibility setting, closes #12698 --- install/data/defaults.json | 3 ++- .../en-GB/admin/settings/reputation.json | 12 ++++++---- public/openapi/read/topic/topic_id.yaml | 4 +++- public/openapi/write/posts/pid/voters.yaml | 2 ++ public/src/client/topic/votes.js | 17 +++++++++----- src/api/posts.js | 22 +++++++++++++------ src/controllers/topics.js | 3 ++- .../3.8.4/downvote-visibility-config.js | 20 +++++++++++++++++ src/views/admin/settings/reputation.tpl | 18 ++++++++++----- src/views/modals/votes.tpl | 2 ++ 10 files changed, 79 insertions(+), 24 deletions(-) create mode 100644 src/upgrades/3.8.4/downvote-visibility-config.js diff --git a/install/data/defaults.json b/install/data/defaults.json index 076a1435d0..a5921ab940 100644 --- a/install/data/defaults.json +++ b/install/data/defaults.json @@ -137,7 +137,8 @@ "sitemapTopics": 500, "maintenanceMode": 0, "maintenanceModeStatus": 503, - "voteVisibility": "privileged", + "upvoteVisibility": "all", + "downvoteVisibility": "privileged", "maximumInvites": 0, "username:disableEdit": 0, "email:disableEdit": 0, diff --git a/public/language/en-GB/admin/settings/reputation.json b/public/language/en-GB/admin/settings/reputation.json index a78d0e3fd5..479069e3a4 100644 --- a/public/language/en-GB/admin/settings/reputation.json +++ b/public/language/en-GB/admin/settings/reputation.json @@ -2,10 +2,14 @@ "reputation": "Reputation Settings", "disable": "Disable Reputation System", "disable-down-voting": "Disable Down Voting", - "vote-visibility": "Vote visibility", - "vote-visibility-all": "Everyone can see votes", - "vote-visibility-loggedin": "Only logged in users can see votes", - "vote-visibility-privileged": "Only privileged users like admins & moderators can see votes", + "upvote-visibility": "Up Vote visibility", + "upvote-visibility-all": "Everyone can see up votes", + "upvote-visibility-loggedin": "Only logged in users can see up 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", "min-rep-upvote": "Minimum reputation to upvote posts", "upvotes-per-day": "Upvotes per day (set to 0 for unlimited upvotes)", diff --git a/public/openapi/read/topic/topic_id.yaml b/public/openapi/read/topic/topic_id.yaml index 366ff32675..f0fde1b6c0 100644 --- a/public/openapi/read/topic/topic_id.yaml +++ b/public/openapi/read/topic/topic_id.yaml @@ -382,7 +382,9 @@ get: type: number downvote:disabled: type: number - voteVisibility: + upvoteVisibility: + type: string + downvoteVisibility: type: string feeds:disableRSS: type: number diff --git a/public/openapi/write/posts/pid/voters.yaml b/public/openapi/write/posts/pid/voters.yaml index 868b587c36..80647dd420 100644 --- a/public/openapi/write/posts/pid/voters.yaml +++ b/public/openapi/write/posts/pid/voters.yaml @@ -28,6 +28,8 @@ get: type: number downvoteCount: type: number + showUpvotes: + type: boolean showDownvotes: type: boolean upvoters: diff --git a/public/src/client/topic/votes.js b/public/src/client/topic/votes.js index d78d197f27..ae690de93a 100644 --- a/public/src/client/topic/votes.js +++ b/public/src/client/topic/votes.js @@ -9,17 +9,24 @@ define('forum/topic/votes', [ Votes.addVoteHandler = function () { _showTooltip = {}; - if (canSeeVotes()) { + if (canSeeUpVotes()) { components.get('topic').on('mouseenter', '[data-pid] [component="post/vote-count"]', loadDataAndCreateTooltip); components.get('topic').on('mouseleave', '[data-pid] [component="post/vote-count"]', destroyTooltip); } }; - function canSeeVotes() { - const { voteVisibility, privileges } = ajaxify.data; + function canSeeUpVotes() { + const { upvoteVisibility, privileges } = ajaxify.data; return privileges.isAdminOrMod || - voteVisibility === 'all' || - (voteVisibility === 'loggedin' && config.loggedIn); + upvoteVisibility === 'all' || + (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() { diff --git a/src/api/posts.js b/src/api/posts.js index 2bf4a7c3d2..4e3917a008 100644 --- a/src/api/posts.js +++ b/src/api/posts.js @@ -314,12 +314,19 @@ postsAPI.getVoters = async function (caller, data) { } const { pid } = data; 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]]'); } - 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([ - db.getSetMembers(`pid:${data.pid}:upvote`), + showUpvotes ? db.getSetMembers(`pid:${data.pid}:upvote`) : [], showDownvotes ? db.getSetMembers(`pid:${data.pid}:downvote`) : [], ]); @@ -331,6 +338,7 @@ postsAPI.getVoters = async function (caller, data) { return { upvoteCount: upvoters.length, downvoteCount: downvoters.length, + showUpvotes: showUpvotes, showDownvotes: showDownvotes, upvoters: upvoters, downvoters: downvoters, @@ -343,7 +351,7 @@ postsAPI.getUpvoters = async function (caller, data) { } const { pid } = data; 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]]'); } @@ -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); if (!isArray) { cids = [cids]; @@ -389,8 +397,8 @@ async function canSeeVotes(uid, cids) { ( cidToAllowed[cid] && ( - meta.config.voteVisibility === 'all' || - (meta.config.voteVisibility === 'loggedin' && parseInt(uid, 10) > 0) + meta.config[type] === 'all' || + (meta.config[type] === 'loggedin' && parseInt(uid, 10) > 0) ) ) ); diff --git a/src/controllers/topics.js b/src/controllers/topics.js index 6a3eba85c5..d83ce8e602 100644 --- a/src/controllers/topics.js +++ b/src/controllers/topics.js @@ -97,7 +97,8 @@ topicsController.get = async function getTopic(req, res, next) { topicData.topicStaleDays = meta.config.topicStaleDays; topicData['reputation:disabled'] = meta.config['reputation: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['signatures:hideDuplicates'] = meta.config['signatures:hideDuplicates']; topicData.bookmarkThreshold = meta.config.bookmarkThreshold; diff --git a/src/upgrades/3.8.4/downvote-visibility-config.js b/src/upgrades/3.8.4/downvote-visibility-config.js new file mode 100644 index 0000000000..d3ac559250 --- /dev/null +++ b/src/upgrades/3.8.4/downvote-visibility-config.js @@ -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'); + } + }, +}; diff --git a/src/views/admin/settings/reputation.tpl b/src/views/admin/settings/reputation.tpl index b086439498..daedbd76cb 100644 --- a/src/views/admin/settings/reputation.tpl +++ b/src/views/admin/settings/reputation.tpl @@ -14,12 +14,20 @@ +
+ + +
- - + + +
diff --git a/src/views/modals/votes.tpl b/src/views/modals/votes.tpl index 6c0b54e277..e9a31422ec 100644 --- a/src/views/modals/votes.tpl +++ b/src/views/modals/votes.tpl @@ -1,9 +1,11 @@ +{{{ if showUpvotes }}}

[[global:upvoters]] ({upvoteCount})

{{{ each upvoters }}} {buildAvatar(@value, "24px", true)} {{{ end }}}
+{{{ end }}} {{{ if showDownvotes }}}

[[global:downvoters]] ({downvoteCount})

From bf27e3800363c86f2089bddc1747fd7851624c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 18 Jul 2024 18:00:12 -0400 Subject: [PATCH 2/3] send the location of widget to render hooks --- src/widgets/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/widgets/index.js b/src/widgets/index.js index 9f31e60805..0478b8dc3a 100644 --- a/src/widgets/index.js +++ b/src/widgets/index.js @@ -41,11 +41,13 @@ async function renderLocation(location, data, uid, options) { return []; } - const renderedWidgets = await Promise.all(widgetsAtLocation.map(widget => renderWidget(widget, uid, options))); + const renderedWidgets = await Promise.all( + widgetsAtLocation.map(widget => renderWidget(widget, uid, options, location)) + ); return renderedWidgets; } -async function renderWidget(widget, uid, options) { +async function renderWidget(widget, uid, options, location) { if (!widget || !widget.data || (!!widget.data['hide-mobile'] && options.req.useragent.isMobile)) { return; } @@ -69,6 +71,7 @@ async function renderWidget(widget, uid, options) { data: widget.data, req: options.req, res: options.res, + location, }); if (!data) { From d1663ac26bcc49157d6f69cbb456ef101c7c8c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bar=C4=B1=C5=9F=20Soner=20U=C5=9Fakl=C4=B1?= Date: Thu, 18 Jul 2024 18:01:38 -0400 Subject: [PATCH 3/3] chore: up widgets --- install/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/package.json b/install/package.json index 94abfdee3c..9bf2e4e045 100644 --- a/install/package.json +++ b/install/package.json @@ -108,7 +108,7 @@ "nodebb-theme-lavender": "7.1.8", "nodebb-theme-peace": "2.2.6", "nodebb-theme-persona": "13.3.25", - "nodebb-widget-essentials": "7.0.17", + "nodebb-widget-essentials": "7.0.18", "nodemailer": "6.9.13", "nprogress": "0.2.0", "passport": "0.7.0",