Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nodebb-plugin-total-vote-count

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nodebb-plugin-total-vote-count - npm Package Compare versions

Comparing version 1.3.0 to 1.3.1

package-lock.json

7

CHANGELOG.md
# Changelog
## [1.3.1](https://github.com/oplik0/nodebb-plugin-total-vote-count/compare/v1.3.0...v1.3.1) (2024-03-24)
### Bug Fixes
* dont calculate totalVoteCount on every page load ([#21](https://github.com/oplik0/nodebb-plugin-total-vote-count/issues/21)) ([ef969d2](https://github.com/oplik0/nodebb-plugin-total-vote-count/commit/ef969d2c5205798fd4b224a74fc9fa0d6f414ff0))
## [1.3.0](https://github.com/oplik0/nodebb-plugin-total-vote-count/compare/v1.2.1...v1.3.0) (2024-03-20)

@@ -4,0 +11,0 @@

131

library.js
'use strict';
const winston = require.main.require('winston');
const _ = require.main.require('lodash');
const db = require.main.require('./src/database');
const topics = require.main.require('./src/topics');
const batch = require.main.require('./src/batch');
const socketAdmin = require.main.require('./src/socket.io/admin');
const plugin = module.exports;
plugin.init = async function (params) {
const { router } = params;
const routeHelpers = require.main.require('./src/routes/helpers');
routeHelpers.setupAdminPageRoute(router, '/admin/plugins/total-vote-count', [], (req, res) => {
res.render('admin/plugins/total-vote-count', {
title: 'Total Vote Count',
});
});
};
plugin.addAdminNavigation = async function (header) {
header.plugins.push({
route: '/plugins/total-vote-count',
icon: 'fa-book',
name: 'Total vote count',
});
return header;
};
plugin.getTopics = async (hookData) => {
let voteData;
try {
voteData = await db.getSortedSetsMembersWithScores(
hookData.topics.map(t => `tid:${t.tid}:posts:votes`)
);
} catch (e) {
winston.error(`Error getting vote data ${e}`);
return hookData;
}
for (const [index, topic] of Object.entries(hookData.topics)) {
if (topic) {
for (const { score } of voteData[index]) {
topic.votes += score;
}
hookData.topics.forEach((t) => {
if (t && t.hasOwnProperty('totalVoteCount')) {
t.votes = parseInt(t.totalVoteCount, 10);
}
}
});
return hookData;

@@ -32,18 +44,87 @@ };

const { tid } = hookData.post;
const topicData = await topics.getTopicFields(tid, ['cid', 'upvotes', 'downvotes', 'pinned']);
const voteData = await db.getSortedSetMembersWithScores(`tid:${tid}:posts:votes`);
await recalculateTotalTopicVotes([tid]);
};
let { votes } = topicData;
for (const { score } of voteData) {
votes += score;
plugin.actionPostMove = async (hookData) => {
await recalculateTotalTopicVotes([hookData.tid, hookData.post.tid]);
};
plugin.actionPostDelete = async (hookData) => {
await recalculateTotalTopicVotes([hookData.post.tid]);
};
plugin.actionPostRestore = async (hookData) => {
await recalculateTotalTopicVotes([hookData.post.tid]);
};
plugin.actionPostsPurge = async (hookData) => {
const tids = _.uniq(hookData.posts.map(p => p && p.tid));
await recalculateTotalTopicVotes(tids);
};
async function recalculateTotalTopicVotes(tids) {
if (!tids.length) {
return;
}
const topicData = await topics.getTopicsFields(tids, [
'tid', 'cid', 'upvotes', 'downvotes', 'pinned',
]);
const voteData = await db.getSortedSetsMembersWithScores(
tids.map(tid => `tid:${tid}:posts:votes`)
);
for (const [index, topic] of Object.entries(topicData)) {
if (topic) {
topic.totalVoteCount = topic.votes;
for (const { score } of voteData[index]) {
topic.totalVoteCount += score;
}
}
}
const promises = [
db.sortedSetAdd('topics:votes', votes, tid),
db.sortedSetAddBulk(topicData.map(t => (['topic:votes', t.totalVoteCount, t.tid]))),
db.setObjectBulk(topicData.map(t => ([`topic:${t.tid}`, { totalVoteCount: t.totalVoteCount }]))),
];
if (!topicData.pinned) {
promises.push(db.sortedSetAdd(`cid:${topicData.cid}:tids:votes`, votes, tid));
const nonPinned = topicData.filter(t => t && !t.pinned);
if (nonPinned.length) {
promises.push(db.sortedSetAddBulk(nonPinned.map(t => ([`cid:${t.cid}:tids:votes`, t.totalVoteCount, t.tid]))));
}
await Promise.all(promises);
}
socketAdmin.plugins.totalVotes = Object.create(null);
socketAdmin.plugins.totalVotes.calculate = async (/* socket */) => {
await batch.processSortedSet('topics:tid', recalculateTotalTopicVotes, {
batch: 500,
});
};
socketAdmin.plugins.totalVotes.revert = async (/* socket */) => {
await batch.processSortedSet('topics:tid', async (tids) => {
let topicData = await db.getObjectsFields(
tids.map(tid => `topic:${tid}`),
['tid', 'cid', 'upvotes', 'downvotes', 'pinned']
);
topicData = topicData.filter(t => t && t.cid);
topicData.forEach((t) => {
t.votes = parseInt(t.upvotes || 0, 10) - parseInt(t.downvotes || 0, 10);
});
const promises = [
db.sortedSetAddBulk(topicData.map(t => ([`topic:votes`, t.votes, t.tid]))),
db.deleteObjectFields(tids.map(tid => `topic:${tid}`), ['totalVoteCount']),
];
const nonPinned = topicData.filter(t => t && !t.pinned);
if (nonPinned.length) {
promises.push(
db.sortedSetAddBulk(nonPinned.map(t => ([`cid:${t.cid}:tids:votes`, t.votes, t.tid])))
);
}
await Promise.all(promises);
}, {
batch: 500,
});
};

2

package.json
{
"name": "nodebb-plugin-total-vote-count",
"version": "1.3.0",
"version": "1.3.1",
"description": "A starter kit for quickly creating NodeBB plugins",

@@ -5,0 +5,0 @@ "main": "library.js",

@@ -6,5 +6,14 @@ {

"hooks": [
{ "hook": "static:app.load", "method": "init" },
{ "hook": "filter:admin.header.build", "method": "addAdminNavigation" },
{ "hook": "filter:topics.get", "method": "getTopics" },
{ "hook": "action:post.updatePostVoteCount", "method": "updatePostVoteCount" }
]
{ "hook": "action:post.updatePostVoteCount", "method": "updatePostVoteCount" },
{ "hook": "action:post.move", "method": "actionPostMove" },
{ "hook": "action:post.delete", "method": "actionPostDelete" },
{ "hook": "action:post.restore", "method": "actionPostRestore" },
{ "hook": "action:posts.purge", "method": "actionPostsPurge" }
],
"modules": {
"../admin/plugins/total-vote-count.js": "./public/admin.js"
}
}

@@ -22,2 +22,3 @@ /**

const assert = require('assert');
const util = require('util');

@@ -29,2 +30,4 @@ const topics = require.main.require('./src/topics');

const sleep = util.promisify(setTimeout);
describe('nodebb-plugin-total-vote-count', () => {

@@ -72,2 +75,3 @@ let authorUid;

await posts.upvote(postData.pid, commenterUid);
await sleep(1000);
let [topic] = await topics.getTopicsByTids([topicData.tid]);

@@ -77,2 +81,3 @@ assert.strictEqual(topic.votes, 1);

await posts.downvote(postData.pid, commenterUid);
await sleep(1000);
[topic] = await topics.getTopicsByTids([topicData.tid]);

@@ -85,2 +90,3 @@ assert.strictEqual(topic.votes, -1);

await posts.upvote(responseData.pid, authorUid);
await sleep(1000);
let [topic] = await topics.getTopicsByTids([topicData.tid]);

@@ -90,2 +96,3 @@ assert.strictEqual(topic.votes, 1);

await posts.downvote(responseData.pid, authorUid);
await sleep(1000);
[topic] = await topics.getTopicsByTids([topicData.tid]);

@@ -98,2 +105,3 @@ assert.strictEqual(topic.votes, -1);

await posts.upvote(responseData.pid, authorUid);
await sleep(1000);
const [topic] = await topics.getTopicsByTids([topicData.tid]);

@@ -106,2 +114,3 @@ assert.strictEqual(topic.votes, 2);

await posts.downvote(responseData.pid, authorUid);
await sleep(1000);
const [topic] = await topics.getTopicsByTids([topicData.tid]);

@@ -108,0 +117,0 @@ assert.strictEqual(topic.votes, 0);

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc